/********************i**************************************************** MeOS - Orienteering Software Copyright (C) 2009-2024 Melin Software HB This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Melin Software HB - software@melin.nu - www.melin.nu Eksoppsvägen 16, SE-75646 UPPSALA, Sweden ************************************************************************/ #include "stdafx.h" #include "oListInfo.h" #include "oEvent.h" #include "gdioutput.h" #include "meos_util.h" #include #include #include "Localizer.h" #include "metalist.h" #include #include "gdifonts.h" #include "generalresult.h" #include "meosexception.h" #include "gdiimpl.h" #include "image.h" struct PrintPostInfo { PrintPostInfo(gdioutput &gdi, const oListParam &par) : gdi(gdi), par(par), keepToghether(false) {} gdioutput &gdi; const oListParam ∥ oCounter counter; bool keepToghether; void reset() {keepToghether = false;} private: PrintPostInfo &operator=(const PrintPostInfo &a) {} }; oListInfo::oListInfo() { listType=EBaseTypeRunner; listSubType=EBaseTypeRunner; calcResults=false; calcTotalResults = false; rogainingResults = false; calculateLiveResults = false; calcCourseClassResults = false; calcCourseResults = false; listPostFilter.resize(_EFilterMax+1, 0); listPostSubFilter.resize(_ESubFilterMax+1, 0); fixedType = false; largeSize = false; supportClasses = true; supportLegs = false; supportParameter = false; supportLarge = false; supportTo = false; supportFrom = false; supportCustomTitle = true; resType = Classwise; supportSplitAnalysis = true; supportInterResults = true; supportPageBreak = true; supportClassLimit = true; needPunches = PunchMode::NoPunch; } oListInfo::~oListInfo(void) { } void oListInfo::replaceType(EPostType find, EPostType replace, bool onlyFirst) { for (auto blp : { &head, &subHead, &listPost, &subListPost }) { for (auto &pp : *blp) { if (pp.type == replace && onlyFirst) return; if (pp.type == find) { pp.type = replace; if (onlyFirst) return; } } } } wstring oListParam::getContentsDescriptor(const oEvent &oe) const { wstring cls; vector classes; oe.getClasses(classes, false); if (classes.size() == selection.size() || selection.empty()) cls = oe.getName(); // All classes else { for (pClass c : classes) { if (selection.count(c->getId())) { if (!cls.empty()) cls += L", "; cls += c->getName(); } } } if (legNumber != -1) return lang.tl(L"Sträcka X#" + getLegName()) + L": " + cls; else return cls; } oPrintPost::oPrintPost() : type(lString), dx(0), dy(0), format(0) { legIndex = -1; linearLegIndex = true; } oPrintPost::oPrintPost(EPostType type, const wstring& text, int format, int dx, int dy, pair index) : type(type), text(text), format(format), dx(dx), dy(dy) { legIndex = index.first; linearLegIndex = index.second; } oPrintPost::oPrintPost(const wstring& image, int style, int dx, int dy, int width, int height) : type(lImage), text(image), format(style), dx(dx), dy(dy), fixedWidth(width), fixedHeight(height) { legIndex = -1; linearLegIndex = true; } bool oListInfo::needRegenerate(const oEvent &oe) const { for(oClassList::const_iterator it = oe.Classes.begin(); it != oe.Classes.end(); ++it) { if (it->isRemoved()) continue; if (!lp.selection.empty() && lp.selection.count(it->getId()) == 0 ) continue; // Not our class int legToCheck = -1; if (needPunches == PunchMode::SpecificPunch) { int to = oControl::getIdIndexFromCourseControlId(lp.useControlIdResultTo).first; int from = oControl::getIdIndexFromCourseControlId(lp.useControlIdResultFrom).first; if (it->wasSQLChanged(legToCheck, to) || it->wasSQLChanged(legToCheck, from) ) return true; } else if (needPunches == PunchMode::AnyPunch) { if (it->wasSQLChanged(legToCheck, -2)) return true; } else { if (it->wasSQLChanged(legToCheck, -1)) return true; } } return false; } static void generateNBestHead(const oListParam &par, oListInfo &li, int ypos) { if (par.filterMaxPer > 0) li.addHead(oPrintPost(lString, lang.tl(L"Visar de X bästa#" + itow(par.filterMaxPer)), normalText, 0, ypos)); } extern gdioutput *gdi_main; static pair getControlName(const oEvent &oe, int courseContolId) { pair idt = oControl::getIdIndexFromCourseControlId(courseContolId); pControl to = oe.getControl(idt.first); wstring toS; bool name = false; if (to) { if (to->hasName()) { toS = to->getName(); name = true; } else if (to->getFirstNumber()>0) toS = itow(to->getFirstNumber()); else toS = itow(idt.first); if (to->getNumberDuplicates() > 0) toS += L"-" + itow(idt.second + 1); } else toS = itow(idt.first); return make_pair(toS, name); } static wstring getFullControlName(const oEvent &oe, int ctrl) { pair toS = getControlName(oe, ctrl); if (toS.second) return toS.first; else return lang.tl(L"Kontroll X#" + toS.first); } static void getResultTitle(const oEvent &oe, const oListParam &lp, wstring &title) { if (lp.useControlIdResultTo <= 0 && lp.useControlIdResultFrom <= 0) title = lang.tl(L"Resultat - %s"); else if (lp.useControlIdResultTo>0 && lp.useControlIdResultFrom<=0){ pair toS = getControlName(oe, lp.useControlIdResultTo); if (toS.second) title = lang.tl(L"Resultat - %s") + L", " + toS.first; else title = lang.tl(L"Resultat - %s") + L", " + lang.tl(L"vid kontroll X#" + toS.first); } else { wstring fromS = lang.tl(L"Start"), toS = lang.tl(L"Mål"); if (lp.useControlIdResultTo>0) { toS = getControlName(oe, lp.useControlIdResultTo).first; } if (lp.useControlIdResultFrom>0) { fromS = getControlName(oe, lp.useControlIdResultFrom).first; } title = lang.tl(L"Resultat mellan X och Y#" + fromS + L"#" + toS); } } static double adjustmentFactor(double par, double target) { double k = (1.0 - target)/10; double val = max(target, 1.0 - (par * k)); return val; } template class WordMeasure { multimap words; public: WordMeasure() {} void add(const T &word) { if (words.size() > size) { size_t blen = words.begin()->first; if (word.length() <= blen) return; else { words.erase(words.begin()); words.insert(make_pair(word.length(), word)); } } else { words.insert(make_pair(word.length(), word)); } } int measure(const gdioutput &gdi, gdiFonts font, const wchar_t *fontFace, T &longest) { int w = 0; TextInfo ti; HDC hDC = GetDC(gdi.getHWNDTarget()); for (auto it = words.begin(); it != words.end(); ++it) { ti.xp = 0; ti.yp = 0; ti.format = font; ti.text = it->second; ti.font = fontFace != 0 ? fontFace : L""; gdi.calcStringSize(ti, hDC); if (ti.textRect.right > w) { w = ti.textRect.right; longest = ti.text; } } ReleaseDC(gdi.getHWNDTarget(), hDC); return w; } }; int oListInfo::getMaxCharWidth(const oEvent *oe, const gdioutput &gdi, const set &clsSel, const vector< pair > &typeFormats, gdiFonts font, const wchar_t *fontFace, bool large, int minSize) const { vector pps; for (size_t k = 0; k < typeFormats.size(); k++) { pps.push_back(oPrintPost()); pps.back().text = typeFormats[k].second; pps.back().type = typeFormats[k].first; } oListParam par; par.setLegNumberCoded(0); oCounter c; vector< WordMeasure > extras(pps.size()); for (size_t k = 0; k < pps.size(); k++) { wstring extra; switch (pps[k].type) { case lResultModuleNumber: case lResultModuleNumberTeam: if (pps[k].text.length() > 1 && pps[k].text[0] == '@') { wstring tmp; int miLen = 0; for (int j = 0; j < 10; j++) { tmp = MetaList::fromResultModuleNumber(pps[k].text.substr(1), j, tmp); if (tmp.length() > miLen / 2) { miLen = tmp.length(); extras[k].add(tmp); } } } else extra = L"999"; break; case lRunnerCardVoltage: extra = L"3.00 V"; break; case lPunchName: case lControlName: case lPunchNamedTime: case lPunchTeamTotalNamedTime: { wstring maxcn = lang.tl("Mål"); vector ctrl; oe->getControls(ctrl, false); for (pControl c : ctrl) { wstring cn = c->getName(); if (cn.length() > maxcn.length()) maxcn.swap(cn); } if (pps[k].type == lPunchNamedTime) extra = maxcn + L": 50:50 (50:50)"; if (pps[k].type == lPunchTeamTotalNamedTime) extra = maxcn + L": 2:50:50 (50:50)"; else maxcn.swap(extra); } break; case lRunnerFinish: case lRunnerCheck: case lPunchAbsTime: case lRunnerStart: case lTeamStart: extra = L"10:10:00"; break; case lRunnerTotalTimeAfter: case lRunnerClassCourseTimeAfter: case lRunnerTimeAfterDiff: case lRunnerTempTimeAfter: case lRunnerTimeAfter: case lRunnerLostTime: case lTeamTimeAfter: case lTeamLegTimeAfter: case lTeamTotalTimeAfter: case lTeamTimeAdjustment: case lRunnerTimeAdjustment: case lRunnerGeneralTimeAfter: case lPunchTotalTimeAfter: case lPunchTeamTotalTimeAfter: extra = L"+10:00"; break; case lTeamRogainingPointOvertime: case lRunnerRogainingPointOvertime: case lResultModuleTime: case lResultModuleTimeTeam: case lTeamTime: case lTeamGrossTime: case lTeamTotalTime: case lTeamTotalTimeStatus: case lTeamLegTimeStatus: case lTeamTimeStatus: case lRunnerTempTimeStatus: case lRunnerTotalTimeStatus: case lRunnerTotalTime: case lClassStartTime: case lRunnerTime: case lRunnerGrossTime: case lRunnerTimeStatus: case lRunnerStageTime: case lRunnerStageTimeStatus: case lRunnerStageStatus: case lRunnerTimePlaceFixed: case lPunchLostTime: case lPunchTimeSinceLast: case lPunchSplitTime: case lPunchNamedSplit: extra = L"50:50"; break; case lPunchTotalTime: case lPunchTeamTotalTime: extra = L"1:50:50"; break; case lRunnerGeneralTimeStatus: case lClassStartTimeRange: extra = L"50:50 (50:50)"; break; case lTeamRogainingPointReduction: case lRunnerRogainingPointReduction: case lTeamPointAdjustment: case lRunnerPointAdjustment: case lRunnerRogainingPointGross: case lRunnerPlace: case lRunnerPlaceDiff: case lTeamPlaceDiff: case lRunnerTotalPlace: case lRunnerClassCoursePlace: case lRunnerCoursePlace: case lTeamPlace: case lTeamTotalPlace: case lPunchControlPlace: case lPunchControlPlaceAcc: case lPunchControlPlaceTeamAcc: case lRunnerStagePlace: case lRunnerDataA: case lRunnerDataB: case lTeamDataA: case lTeamDataB: case lClassDataA: case lClassDataB: extra = L"99."; break; case lRunnerGeneralPlace: extra = L"99. (99.)"; break; } EPostType type = pps[k].type; if (type == lClubName || type == lRunnerName || type == lTeamName || type == lTeamRunner || type == lTeamClub) extras[k].add(L"IK Friskus Varberg"); if (type == lRunnerGivenName || type == lRunnerFamilyName || type == lRunnerNationality || type == lRunnerLegTeamLeaderName) extras[k].add(L"Karl-Gunnar"); if (type == lRunnerCompleteName || type == lPatrolNameNames || type == lPatrolClubNameNames) extras[k].add(L"Karl-Gunnar Alexandersson"); extras[k].add(extra); } for (size_t k = 0; k < pps.size(); k++) { const oPrintPost &pp = pps[k]; int cardSkip = 0; int skip = 0; wstring last; for (auto crd = oe->Cards.begin(); crd != oe->Cards.end(); ++crd) { if (--skip > 0) continue; skip = cardSkip++; for (auto &p : crd->punches) { pRunner r = crd->tOwner; p.previousPunchTime = 0; const wstring &out = oe->formatPunchString(pp, par, r ? r->getTeam() : nullptr, r, &p, c); if (last == out) break; else last = out; extras[k].add(out); } } for (auto &cls : oe->Classes) { if (cls.isRemoved()) continue; if (!clsSel.empty() && clsSel.count(cls.getId()) == 0) continue; const wstring &out = oe->formatListString(pp, par, 0, 0, 0, pClass(&cls), c); extras[k].add(out); } for (oCourseList::const_iterator it = oe->Courses.begin(); it != oe->Courses.end(); ++it) { if (it->isRemoved()) continue; const wstring &out = oe->formatSpecialString(pp, par, 0, 0, pCourse(&*it), 0, c); extras[k].add(out); } for (oControlList::const_iterator it = oe->Controls.begin(); it != oe->Controls.end(); ++it) { if (it->isRemoved()) continue; const wstring &out = oe->formatSpecialString(pp, par, 0, 0, 0, pControl(&*it), c); extras[k].add(out); } } vector row(pps.size(), 0); vector samples(pps.size()); wstring totWord = L""; for (size_t k = 0; k < pps.size(); k++) { extras[k].measure(gdi, font, fontFace, samples[k]); totWord += samples[k]; } WordMeasure totMeasure; totMeasure.add(totWord); for (oRunnerList::const_iterator it = oe->Runners.begin(); it != oe->Runners.end(); ++it) { if (it->isRemoved()) continue; // Case when runner/team has different class bool teamOK = it->getTeam() && clsSel.count(it->getTeam()->getClassId(false)); if (!clsSel.empty() && (!teamOK && clsSel.count(it->getClassId(true)) == 0)) continue; totWord.clear(); wstring rout; for (size_t k = 0; k < pps.size(); k++) { oPrintPost &pp = pps[k]; pp.legIndex = it->tLeg; pp.linearLegIndex = true; int numIter = 1; if (pp.type == lPunchNamedTime || pp.type == lPunchTime || pp.type == lPunchTeamTime) { row[k] = max(row[k], 10); pRunner r = pRunner(&*it); numIter = (r && r->getCard()) ? r->getCard()->getNumPunches() + 1 : 1; } rout.clear(); while (numIter-- > 0) { const wstring &out = oe->formatListString(pp, par, it->tInTeam, pRunner(&*it), it->Club, pClass(it->getClassRef(true)), c); //row[k] = max(row[k], int(out.length())); if (out.length() > rout.length()) rout = out; if (numIter>0) c.level3++; } if (rout.length() > samples[k].length()) totWord.append(rout); else totWord.append(samples[k]); } totMeasure.add(totWord); } wstring dummy; int w = totMeasure.measure(gdi, font, fontFace, dummy); w = max(w, gdi.scaleLength(minSize)); return int(0.5 + (w + (large ? 5 : 15))/gdi.getScale()); } const wstring & oEvent::formatListString(EPostType type, const pRunner r) const { oPrintPost pp; oCounter ctr; oListParam par; par.setLegNumberCoded(r->tLeg); pp.type = type; return formatListString(pp, par, r->tInTeam, r, r->Club, r->getClassRef(true), ctr); } const wstring & oEvent::formatListString(EPostType type, const pRunner r, const wstring &format) const { oPrintPost pp; oCounter ctr; oListParam par; par.setLegNumberCoded(r->tLeg); pp.type = type; pp.text = format; return formatListString(pp, par, r->tInTeam, r, r->Club, r->getClassRef(true), ctr); } const wstring &oEvent::formatListString(const oPrintPost &pp, const oListParam &par, const pTeam t, const pRunner r, const pClub c, const pClass pc, oCounter &counter) const { const oPrintPost *cpp = &pp; const wstring *tmp = 0; wstring *out = 0; while (cpp) { if (tmp) { if (!out) { out = &StringCache::getInstance().wget(); *out = L""; } out->append(*tmp); } tmp = &formatListStringAux(*cpp, par, t, r, c, pc, counter); cpp = cpp->mergeWithTmp; } if (out) { out->append(*tmp); return *out; } else return *tmp; } const wstring &oEvent::formatPunchString(const oPrintPost &pp, const oListParam &par, const pTeam t, const pRunner r, const oPunch *punch, oCounter &counter) const { const oPrintPost *cpp = &pp; const wstring *tmp = 0; wstring *out = 0; while (cpp) { if (tmp) { if (!out) { out = &StringCache::getInstance().wget(); *out = L""; } out->append(*tmp); } tmp = &formatPunchStringAux(*cpp, par, t, r, punch, counter); cpp = cpp->mergeWithTmp; } if (out) { out->append(*tmp); return *out; } else return *tmp; } const wstring &oEvent::formatSpecialString(const oPrintPost &pp, const oListParam &par, const pTeam t, int legIndex, const pCourse crs, const pControl ctrl, oCounter &counter) const { const oPrintPost *cpp = &pp; const wstring *tmp = 0; wstring *out = 0; while (cpp) { if (tmp) { if (!out) { out = &StringCache::getInstance().wget(); *out = L""; } out->append(*tmp); } tmp = &formatSpecialStringAux(*cpp, par, t, legIndex, crs, ctrl, counter); cpp = cpp->mergeWithTmp; } if (out) { out->append(*tmp); return *out; } else return *tmp; } const wstring &oEvent::formatPunchStringAux(const oPrintPost &pp, const oListParam &par, const pTeam t, const pRunner r, const oPunch *punch, oCounter &counterIn) const { wchar_t bfw[128]; const wstring *wsptr = 0; bfw[0] = 0; pClass pc = r ? r->getClassRef(true) : 0; bool invalidClass = pc && pc->getClassStatus() != oClass::ClassStatus::Normal; oCounter counter(counterIn); static bool reentrantLock = false; if (reentrantLock == true) { reentrantLock = false; throw meosException("Internal list error"); } bool doDefault = false; switch (pp.type) { case lControlName: case lPunchName: if (punch) { pCourse pc = r ? r->getCourse(false) : nullptr; if (punch->isFinish(pc ? pc->getFinishPunchType() : oPunch::PunchFinish)) { wsptr = &lang.tl("Mål"); } else { pControl ctrl = getControl(punch->getControlId()); if (!ctrl) ctrl = getControlByType(punch->type); if (ctrl && ctrl->hasName()) { swprintf_s(bfw, L"%s", ctrl->getName().c_str()); } } } break; case lPunchTimeSinceLast: if (punch && punch->previousPunchTime && r && !invalidClass) { int time = punch->getTimeInt(); int pTime = punch->previousPunchTime; if (pTime > 0 && time > pTime) { int t = time - pTime; wsptr = &formatTime(t); } } break; case lPunchTime: case lPunchTeamTime: case lPunchControlNumber: case lPunchControlCode: case lPunchLostTime: case lPunchControlPlace: case lPunchControlPlaceAcc: case lPunchControlPlaceTeamAcc: case lPunchSplitTime: case lPunchTotalTime: case lPunchTeamTotalTime: case lPunchAbsTime: if (punch && r && !invalidClass) { if (punch->tIndex >= 0) { // Punch in course counter.level3 = punch->tIndex; doDefault = true; break; } switch (pp.type) { case lPunchTime: case lPunchTeamTime: { if (punch->hasTime()) { int off = 0; if (pp.type == lPunchTeamTime && r->getTeam()) off = r->getTeam()->getTotalRunningTimeAtLegStart(r->getLegNumber(), false); swprintf_s(bfw, L"\u2013 (%s)", formatTime(off + punch->getTimeInt() - r->getStartTime(), SubSecond::Off).c_str()); } else { wsptr = &makeDash(L"- (-)"); } break; } case lPunchSplitTime: { swprintf_s(bfw, L"\u2013"); break; } case lPunchControlNumber: { wcscpy_s(bfw, L"\u2013"); break; } case lPunchControlCode: { swprintf_s(bfw, L"%d", punch->getTypeCode()); break; } case lPunchAbsTime: { if (punch->hasTime()) wsptr = &getAbsTime(punch->getTimeInt(), SubSecond::Off); break; } case lPunchTotalTime: { if (punch->hasTime()) wsptr = &formatTime(punch->getTimeInt() - r->getStartTime(), SubSecond::Off); break; } case lPunchTeamTotalTime: { if (punch->hasTime()) { pTeam t = r->getTeam(); if (!t || r->getLegNumber() == 0) wsptr = &formatTime(punch->getTimeInt() - r->getStartTime(), SubSecond::Off); else { int input = t->getTotalRunningTimeAtLegStart(r->getLegNumber(), false); wsptr = &formatTime(input + punch->getTimeInt() - r->getStartTime(), SubSecond::Off); } } break; } } } break; default: doDefault = true; } if (doDefault) { reentrantLock = true; try { const wstring &res = formatListStringAux(pp, par, t, r, r ? r->getClubRef() : 0, r ? r->getClassRef(true) : 0, counter); reentrantLock = false; return res; } catch (...) { reentrantLock = false; throw; } } if (pp.type != lString && (wsptr == 0 || wsptr->empty()) && bfw[0] == 0) return _EmptyWString; else if (wsptr) { if (pp.text.empty()) return *wsptr; else { swprintf_s(bfw, pp.text.c_str(), wsptr->c_str()); wstring &res = StringCache::getInstance().wget(); res = bfw; return res; } } else { if (pp.text.empty()) { wstring &res = StringCache::getInstance().wget(); res = bfw; return res; } else { wchar_t bf2[512]; swprintf_s(bf2, pp.text.c_str(), bfw); wstring &res = StringCache::getInstance().wget(); res = bf2; return res; } } } const wstring &oEvent::formatSpecialStringAux(const oPrintPost &pp, const oListParam &par, const pTeam t, int legIndex, const pCourse pc, const pControl ctrl, const oCounter &counter) const { wchar_t bfw[512]; const wstring *wsptr=0; bfw[0] = 0; static bool reentrantLock = false; if (reentrantLock == true) { reentrantLock = false; throw meosException("Internal list error"); } switch (pp.type) { case lCourseLength: if (pc) { int len = pc->getLength(); if (len > 0) swprintf_s(bfw, L"%d", len); } break; case lTeamCourseName: case lCourseName: case lRunnerCourse: if (pc) { wsptr = &pc->getName(); } break; case lCourseNumber: case lTeamCourseNumber: if (pc) { wsptr = &itow(pc->getId()); } break; case lRunnerLegNumberAlpha: if (t && t->getClassRef(false) && legIndex >= 0) { wstring legStr = t->getClassRef(false)->getLegNumber(legIndex); wcscpy_s(bfw, legStr.c_str()); } break; case lRunnerLegNumber: if (t && t->getClassRef(false) && legIndex >= 0) { int legNumber, legOrder; t->getClassRef(false)->splitLegNumberParallel(legIndex, legNumber, legOrder); wsptr = &itow(legNumber+1); } break; case lCourseClimb: { int len = pc ? pc->getDCI().getInt("Climb") : 0; if (len > 0) swprintf_s(bfw, L"%d", len); } break; case lCourseUsage: if (pc) { wsptr = &itow(pc->getNumUsedMaps(false)); } break; case lCourseUsageNoVacant: if (pc) { wsptr = &itow(pc->getNumUsedMaps(true)); } break; case lCourseNumControls: if (pc) wsptr = &itow(pc->getNumControls()); break; case lCourseClasses: if (pc) { vector cls; pc->getClasses(cls); wstring tmp; for (size_t k = 0; k < cls.size(); k++) { if (k > 0) tmp += L", "; tmp += cls[k]->getName(); if (tmp.length() > 100) { tmp += L", ..."; break; } } wcsncpy_s(bfw, tmp.c_str(), 256); } break; case lControlName: if (ctrl) wcsncpy_s(bfw, ctrl->getName().c_str(), 128); break; case lControlCourses: if (ctrl) { vector crs; ctrl->getCourses(crs); if (crs.size() == Courses.size()) { wsptr = &lang.tl("Alla"); break; } wstring tmp; for (size_t k = 0; k < crs.size(); k++) { if (k > 0) tmp += L", "; tmp += crs[k]->getName(); if (tmp.length() > 100) { tmp += L", ..."; break; } } wcsncpy_s(bfw, tmp.c_str(), 256); } break; case lControlClasses: if (ctrl) { vector cls; ctrl->getClasses(cls); if (cls.size() == getNumClasses()) { wsptr = &lang.tl("Alla"); break; } wstring tmp; for (size_t k = 0; k < cls.size(); k++) { if (k > 0) tmp += L", "; tmp += cls[k]->getName(); if (tmp.length() > 100) { tmp += L", ..."; break; } } wcsncpy_s(bfw, tmp.c_str(), 256); } break; case lControlVisitors: if (ctrl) wsptr = &itow(ctrl->getNumVisitors(false)); break; case lControlPunches: if (ctrl) wsptr = &itow(ctrl->getNumVisitors(true)); break; case lControlMedianLostTime: if (ctrl) wsptr = &formatTime(ctrl->getMissedTimeMedian(), SubSecond::Off); break; case lControlMaxLostTime: if (ctrl) wsptr = &formatTime(ctrl->getMissedTimeMax(), SubSecond::Off); break; case lControlMistakeQuotient: if (ctrl) { wstring tmp = itow(ctrl->getMistakeQuotient()); tmp += L"%"; wcsncpy_s(bfw, tmp.c_str(), 20); } break; case lControlRunnersLeft: if (ctrl) wsptr = &itow(ctrl->getNumRunnersRemaining()); break; case lControlCodes: if (ctrl) { vector numbers; ctrl->getNumbers(numbers); wstring tmp; for (size_t j = 0; j < numbers.size(); j++) { if (j > 0) tmp += L", "; tmp += itow(numbers[j]); } wcsncpy_s(bfw, tmp.c_str(), 256); } break; default: { reentrantLock = true; try { const wstring &res = formatListStringAux(pp, par, t, t ? t->getRunner(legIndex) : 0, t ? t->getClubRef() : 0, t ? t->getClassRef(false) : 0, counter); reentrantLock = false; return res; } catch(...) { reentrantLock = false; throw; } } } if (pp.type!=lString && (wsptr==0 || wsptr->empty()) && bfw[0]==0) return _EmptyWString; else if (wsptr) { if (pp.text.empty()) return *wsptr; else { swprintf_s(bfw, pp.text.c_str(), wsptr->c_str()); wstring &res = StringCache::getInstance().wget(); res = bfw; return res; } } else { if (pp.text.empty()) { wstring &res = StringCache::getInstance().wget(); res = bfw; return res; } else { wchar_t bf2[512]; swprintf_s(bf2, pp.text.c_str(), bfw); wstring &res = StringCache::getInstance().wget(); res = bf2; return res; } } } const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListParam &par, const pTeam t, const pRunner r, const pClub c, const pClass pc, const oCounter &counter) const { wchar_t wbf[512]; const wstring *wsptr=0; wbf[0]=0; SubSecond mode = useSubSecond() ? SubSecond::On : SubSecond::Auto; auto noTimingRunner = [&]() { return (pc ? pc->getNoTiming() : false) || (r ? (r->getStatusComputed(true) == StatusNoTiming || r->noTiming()) : false); }; auto noTimingTeam = [&]() { return (pc ? pc->getNoTiming() : false) || (t ? (t->getStatusComputed(true) == StatusNoTiming || t->noTiming()): false); }; bool invalidClass = pc && pc->getClassStatus() != oClass::ClassStatus::Normal; int legIndex = pp.legIndex; if(pc && MetaList::isAllLegType(pp.type)) { if (legIndex == -1) { if (r) legIndex = r->getLegNumber(); else legIndex = pc->getNumStages() - 1; } else if (legIndex < max(1, pc->getNumStages())) legIndex = pc->getLinearIndex(pp.legIndex, pp.linearLegIndex); } else if (pc && !MetaList::isResultModuleOutput(pp.type) && !MetaList::isAllStageType(pp.type)) { if (legIndex == -1) { if (r) legIndex = r->getLegNumber(); else legIndex = pc->getNumStages() - 1; } else legIndex = pc->getLinearIndex(pp.legIndex, pp.linearLegIndex); } switch ( pp.type ) { case lClassName: if (invalidClass) swprintf_s(wbf, L"%s (%s)", pc->getName().c_str(), lang.tl("Struken").c_str()); else wsptr=pc ? &pc->getName() : 0; break; case lResultDescription: { wstring title; getResultTitle(*this, par, title); wcscpy_s(wbf, title.c_str()); } break; case lTimingFromName: if (par.useControlIdResultFrom > 0) wcscpy_s(wbf, getFullControlName(*this, par.useControlIdResultFrom).c_str()); else wsptr = &lang.tl(L"Start"); break; case lTimingToName: if (par.useControlIdResultTo > 0) wcscpy_s(wbf, getFullControlName(*this, par.useControlIdResultTo).c_str()); else wsptr = &lang.tl(L"Mål"); break; case lClassLength: if (pc) { wcscpy_s(wbf, pc->getLength(par.relayLegIndex).c_str()); } break; case lClassStartName: if (pc) wcscpy_s(wbf, pc->getDI().getString("StartName").c_str()); break; case lClassStartTime: case lClassStartTimeRange: if (pc) { int first, last; pc->getStartRange(legIndex, first, last); if (pc->hasFreeStart() || pc->hasRequestStart()) wsptr = &lang.tl("Fri starttid"); else if (first > 0 && first == last) { if (oe->useStartSeconds()) wsptr = &oe->getAbsTime(first); else wsptr = &oe->getAbsTimeHM(first); } else if (pp.type == lClassStartTimeRange) { wstring range = oe->getAbsTimeHM(first) + makeDash(L" - ") + oe->getAbsTimeHM(last); wcscpy_s(wbf, range.c_str()); } } break; case lClassResultFraction: if (pc && !invalidClass) { int total, finished, dns; pc->getNumResults(par.getLegNumber(pc), total, finished, dns); swprintf_s(wbf, L"(%d / %d)", finished, total); } break; case lCourseLength: case lCourseName: case lRunnerCourse: case lCourseNumber: if (r) { pCourse crs = r->getCourse(false); return formatSpecialStringAux(pp, par, t, 0, crs, 0, counter); } break; case lTeamCourseNumber: case lTeamCourseName: if (r && pc && legIndex < pc->getNumStages()) { pCourse crs = r->getCourse(false); return formatSpecialStringAux(pp, par, t, 0, crs, 0, counter); } else if (t && pc && legIndex < pc->getNumStages()) { pCourse crs = pc->getCourse(legIndex, t->getStartNo()); return formatSpecialStringAux(pp, par, t, 0, crs, 0, counter); } break; case lTeamLegName: if (pc) { if (legIndex < pc->getNumStages()) wcscpy_s(wbf, pc->getLegNumber(legIndex).c_str()); } break; case lClassAvailableMaps: if (pc) { int n = pc->getNumRemainingMaps(false); if (n != numeric_limits::min()) wsptr = &itow(n); } break; case lClassTotalMaps: if (pc) { int n = pc->getNumberMaps(); if (n > 0) wsptr = &itow(n); } break; case lClassNumEntries: if (pc) { int n = pc->getNumRunners(true, true, true); wsptr = &itow(n); } break; case lClassDataA: if (pc) wsptr = &itow(pc->getDCI().getInt("DataA")); break; case lClassDataB: if (pc) wsptr = &itow(pc->getDCI().getInt("DataB")); break; case lClassTextA: if (pc) wsptr = &pc->getDCI().getString("TextA"); break; case lCourseClimb: case lCourseUsageNoVacant: case lCourseUsage: if (r) { pCourse crs = r->getCourse(false); return formatSpecialStringAux(pp, par, t, 0, crs, 0, counter); } break; case lCourseNumControls: if (r) { pCourse crs = r->getCourse(true); return formatSpecialStringAux(pp, par, t, 0, crs, 0, counter); } break; case lCourseShortening: if (r) { int sh = r->getNumShortening(); if (sh > 0) swprintf_s(wbf, L"%d", sh); } break; case lCmpName: wsptr = &getName(); break; case lCmpDate: wsptr = &getDate(); break; case lCurrentTime: wcscpy_s(wbf, getCurrentTimeS().c_str()); break; case lRunnerClub: wsptr = (r && r->Club) ? &r->Club->getDisplayName() : 0; break; case lRunnerFinish: if (r && !invalidClass) { if (pp.resultModuleIndex == -1) wsptr = &r->getFinishTimeS(false, mode); else wsptr = &r->getTempResult(pp.resultModuleIndex).getFinishTimeS(this, mode); } break; case lRunnerStart: case lRunnerStartCond: case lRunnerStartZero: if (r) { if ((pp.type == lRunnerStartCond || pp.type == lRunnerStartZero) && pc && !pc->hasFreeStart()) { int fs, ls; pc->getStartRange(legIndex, fs, ls); if (fs>0 && fs == ls) { break; // Common start time, skip } } if (r->getStatus() == StatusCANCEL) { wsptr = &oEvent::formatStatus(StatusCANCEL, true); } else if (r->startTimeAvailable()) { if (pp.type != lRunnerStartZero) wsptr = &r->getStartTimeCompact(); else { int st = r->getStartTime(); wsptr = &formatTimeMS(st-oe->getFirstStart(), true); } } else wsptr = &makeDash(L"-"); } break; case lRunnerCheck: if (r && !invalidClass && r->Card) { oPunch *punch = r->Card->getPunchByType(oPunch::PunchCheck); if (punch && punch->hasTime()) wsptr = &getAbsTime(punch->getTimeInt()); else wsptr = &makeDash(L"-"); } break; case lRunnerName: wsptr = r ? &r->getName() : 0; break; case lRunnerGivenName: if (r) wcscpy_s(wbf, r->getGivenName().c_str()); break; case lRunnerFamilyName: if (r) wcscpy_s(wbf, r->getFamilyName().c_str()); break; case lRunnerCompleteName: if (r) wcscpy_s(wbf, r->getCompleteIdentification().c_str()); break; case lRunnerLegTeamLeaderName: { pRunner rr = r; if (t && r) rr = t->getRunnerBestTimePar(r->getLegNumber()); else if (t) rr = t->getRunnerBestTimePar(legIndex); if (rr) swprintf_s(wbf, L"%s", rr->formatName(oRunner::NameFormat::InitLast).c_str()); } break; case lPatrolNameNames: if (t) { pRunner r1 = t->getRunner(0); pRunner r2 = t->getRunner(1); if (r1 && r2 && r2->tParentRunner != r1) { swprintf_s(wbf, L"%s / %s", r1->getName().c_str(),r2->getName().c_str()); } else if (r1) { wsptr = &r1->getName(); } else if (r2) { wsptr = &r2->getName(); } } else { wsptr = r ? &r->getName() : 0; } break; case lPatrolClubNameNames: if (t) { pRunner r1 = t->getRunner(0); pRunner r2 = t->getRunner(1); pClub c1 = r1 ? r1->Club : 0; pClub c2 = r2 ? r2->Club : 0; if (c1 == c2) c2 = 0; if (c1 && c2) { swprintf_s(wbf, L"%s / %s", c1->getDisplayName().c_str(),c2->getDisplayName().c_str()); } else if (c1) { wsptr = &c1->getDisplayName(); } else if (c2) { wsptr = &c2->getDisplayName(); } } else { wsptr = r && r->Club ? &r->Club->getDisplayName() : 0; } break; case lRunnerTime: if (r && !invalidClass) { if (pp.resultModuleIndex == -1) wsptr = &r->getRunningTimeS(true, mode); else wsptr = &r->getTempResult(pp.resultModuleIndex).getRunningTimeS(0, mode); if (r->getNumShortening() > 0) { swprintf_s(wbf, L"*%s", wsptr->c_str()); wsptr = 0; } } break; case lRunnerGrossTime: if (r && !invalidClass) { int tm = r->getRunningTime(true); if (tm > 0) tm -= r->getTimeAdjustment(true); wsptr = &formatTime(tm); } break; case lRunnerTimeStatus: if (r) { if (invalidClass) wsptr = &lang.tl("Struken"); else if (pp.resultModuleIndex == -1) { bool ok = r->prelStatusOK(true, true, true); if (ok && !noTimingRunner()) { wsptr = &r->getRunningTimeS(true, mode); if (r->getNumShortening() > 0) { swprintf_s(wbf, L"*%s", wsptr->c_str()); wsptr = 0; } else if (r->getStatusComputed(true) == StatusOutOfCompetition) { swprintf_s(wbf, L"(%s)", wsptr->c_str()); wsptr = 0; } } else { if (ok) wsptr = &formatStatus(StatusOK, true); else wsptr = &r->getStatusS(true, true); } } else { const oAbstractRunner::TempResult &res = r->getTempResult(pp.resultModuleIndex); if (res.isStatusOK() && !noTimingRunner()) { wsptr = &res.getRunningTimeS(0, mode); if (r->getNumShortening() > 0) { swprintf_s(wbf, L"*%s", wsptr->c_str()); wsptr = 0; } else if (res.getStatus() == StatusOutOfCompetition) { swprintf_s(wbf, L"(%s)", wsptr->c_str()); wsptr = 0; } } else wsptr = &res.getStatusS(StatusOK); } } break; case lRunnerGeneralTimeStatus: if (r) { if (invalidClass) wsptr = &lang.tl("Struken"); else if (pp.resultModuleIndex == -1) { if (r->prelStatusOK(true, true, true) && !noTimingRunner()) { wstring timeStatus = r->getRunningTimeS(true, mode); if (r->hasInputData() || (r->getLegNumber() > 0 && !r->isPatrolMember())) { RunnerStatus ts = r->getTotalStatus(); int rt = r->getTotalRunningTime(); if (ts == StatusOK || (ts == StatusUnknown && rt > 0)) { wstring vts = formatTime(rt) + L" (" + timeStatus + L")"; swap(vts, timeStatus); } else { wstring vts = formatStatus(ts, true) + L" (" + timeStatus + L")"; swap(vts, timeStatus); } } if (r->getNumShortening() > 0) { swprintf_s(wbf, L"*%s", timeStatus.c_str()); } else { wcscpy_s(wbf, timeStatus.c_str()); } } else wsptr = &r->getStatusS(true, true); } else { const oAbstractRunner::TempResult &res = r->getTempResult(pp.resultModuleIndex); if (res.isStatusOK() && !noTimingRunner()) { wsptr = &res.getRunningTimeS(0, mode); if (r->getNumShortening() > 0) { swprintf_s(wbf, L"*%s", wsptr->c_str()); wsptr = 0; } else if (res.getStatus() == StatusOutOfCompetition) { swprintf_s(wbf, L"(%s)", wsptr->c_str()); wsptr = 0; } } else wsptr = &res.getStatusS(StatusOK); } } break; break; case lRunnerGeneralTimeAfter: if (r && pc && !invalidClass && !noTimingRunner()) { if (pp.resultModuleIndex == -1) { if (r->hasInputData() || (r->getLegNumber() > 0 && !r->isPatrolMember())) { int tleg = r->tLeg >= 0 ? r->tLeg:0; if (r->getTotalStatus()==StatusOK) { if ( (t && t->getNumShortening(tleg) == 0) || (!t && r->getNumShortening() == 0)) { int after = r->getTotalRunningTime() - pc->getTotalLegLeaderTime(oClass::AllowRecompute::Yes, tleg, true, true); if (after > 0) swprintf_s(wbf, L"+%s", formatTimeMS(after, false, mode).c_str()); } else { wsptr = &makeDash(L"-"); } } } else { int tleg=r->tLeg>=0 ? r->tLeg:0; if (r->tStatus==StatusOK && pc && !noTimingRunner()) { if (r->getNumShortening() == 0) { int after = r->getRunningTime(true) - pc->getBestLegTime(oClass::AllowRecompute::Yes, tleg, true); if (after > 0) swprintf_s(wbf, L"+%s", formatTimeMS(after, false, mode).c_str()); } else { wsptr = &makeDash(L"-"); } } } } else { int after = r->getTempResult(pp.resultModuleIndex).getTimeAfter(); if (after > 0) swprintf_s(wbf, L"+%s", formatTimeMS(after, false, mode).c_str()); } } break; case lRunnerTimePerKM: if (r && !invalidClass && r->prelStatusOK(true, true, true)) { const pCourse pc = r->getCourse(false); if (pc) { int t = r->getRunningTime(false); int len = pc->getLength(); if (len > 0 && t > 0) { int sperkm = (1000 * t) / len; wsptr = &formatTime(sperkm, SubSecond::Off); } } } break; case lRunnerTotalTime: if (r && !invalidClass) { if (pp.resultModuleIndex == -1) wsptr = &r->getTotalRunningTimeS(mode); else wsptr = &r->getTempResult(pp.resultModuleIndex).getRunningTimeS(r->getTotalTimeInput(), mode); } break; case lRunnerTotalTimeStatus: if (invalidClass) wsptr = &lang.tl("Struken"); else if (r) { if (pp.resultModuleIndex == -1) { if ((r->getTotalStatus()==StatusOK || (r->getTotalStatus()==StatusUnknown && r->prelStatusOK(true, true, true) && r->getInputStatus() == StatusOK) ) && !noTimingRunner()) { wsptr = &r->getTotalRunningTimeS(mode); if (r->getNumShortening() > 0) { swprintf_s(wbf, L"*%s", wsptr->c_str()); wsptr = 0; } } else wsptr = &r->getTotalStatusS(true); } else { const oAbstractRunner::TempResult &res = r->getTempResult(pp.resultModuleIndex); RunnerStatus input = r->getTotalStatusInput(); if (input == StatusOK && res.getStatus() == StatusOK && !noTimingRunner()) { wsptr = &res.getRunningTimeS(r->getTotalTimeInput(), mode); if (r->getNumShortening() > 0) { swprintf_s(wbf, L"*%s", wsptr->c_str()); wsptr = 0; } } else wsptr = &res.getStatusS(input); } } break; case lRunnerTempTimeStatus: if (invalidClass) wsptr = &lang.tl("Struken"); else if (r) { if (showResultTime(r->tempStatus, r->tempRT) && !noTimingRunner()) wcscpy_s(wbf, formatTime(r->tempRT).c_str()); else wcscpy_s(wbf, formatStatus(r->tempStatus, true).c_str() ); } break; case lRunnerCardVoltage: if (r && r->getCard()) { wcscpy_s(wbf, r->getCard()->getCardVoltage().c_str()); } break; case lRunnerStageNumber: if (pp.legIndex >= 0) swprintf_s(wbf, L"%d", pp.legIndex + 1); break; case lRunnerStageTimeStatus: if (invalidClass) wsptr = &lang.tl("Struken"); else if (r) { wstring tmp; int time, d; RunnerStatus st = r->getStageResult(pp.legIndex, time, d, d); if (showResultTime(st, time) && !noTimingRunner()) wcscpy_s(wbf, formatTime(time).c_str()); else wcscpy_s(wbf, formatStatus(st, true).c_str()); } break; case lRunnerStageTime: if (invalidClass) wsptr = &lang.tl("Struken"); else if (r) { wstring tmp; int time, d; RunnerStatus st = r->getStageResult(pp.legIndex, time, d, d); if (time > 0 && !noTimingRunner()) wcscpy_s(wbf, formatTime(time).c_str()); } break; case lRunnerStageStatus: if (invalidClass) wsptr = &lang.tl("Struken"); else if (r) { wstring tmp; int time, d; RunnerStatus st = r->getStageResult(pp.legIndex, time, d, d); wcscpy_s(wbf, formatStatus(st, true).c_str()); } break; case lRunnerStagePoints: if (!invalidClass && r) { int points, d; RunnerStatus st = r->getStageResult(pp.legIndex, d, points, d); swprintf_s(wbf, L"%d", points); } break; case lRunnerPlace: if (r && !invalidClass && !noTimingRunner()) { if (pp.resultModuleIndex == -1) wcscpy_s(wbf, r->getPrintPlaceS(pp.text.empty()).c_str() ); else wsptr = &r->getTempResult(pp.resultModuleIndex).getPrintPlaceS(pp.text.empty()); } break; case lRunnerTotalPlace: if (r && !invalidClass && !noTimingRunner()) wcscpy_s(wbf, r->getPrintTotalPlaceS(pp.text.empty()).c_str() ); break; case lRunnerStagePlace: if (r && !invalidClass && !noTimingRunner()) { int d, place; wstring tmp; r->getStageResult(pp.legIndex, d, d, place); if (place > 0) { tmp = itow(place); if (pp.text.empty()) tmp += L"."; } wcscpy_s(wbf, tmp.c_str()); } break; case lRunnerGeneralPlace: if (r && !invalidClass && pc && !noTimingRunner()) { if (pp.resultModuleIndex == -1) { if (r->hasInputData() || (r->getLegNumber() > 0 && !r->isPatrolMember())) { wstring iPlace; if (pc->getClassType() != oClassPatrol) iPlace = r->getPrintPlaceS(true); wstring tPlace = r->getPrintTotalPlaceS(true); wstring v; if (iPlace.empty()) v = tPlace; else { if (tPlace.empty()) tPlace = makeDash(L"-"); v = tPlace + L" (" + iPlace + L")"; } wcscpy_s(wbf, v.c_str()); } else wcscpy_s(wbf, r->getPrintPlaceS(pp.text.empty()).c_str() ); } else wsptr = &r->getTempResult(pp.resultModuleIndex).getPrintPlaceS(pp.text.empty()); } break; case lRunnerClassCoursePlace: if (r && !invalidClass && !noTimingRunner()) { int p = r->getCoursePlace(true); if (p>0 && p<10000) swprintf_s(wbf, L"%d.", p); } break; case lRunnerCoursePlace: if (r && !invalidClass && !noTimingRunner()) { int p = r->getCoursePlace(false); if (p>0 && p<10000) swprintf_s(wbf, L"%d.", p); } break; case lRunnerPlaceDiff: if (r && !invalidClass && !noTimingRunner()) { int p = r->getTotalPlace(); if (r->getTotalStatus() == StatusOK && p > 0 && r->inputPlace>0) { int pd = p - r->inputPlace; if (pd > 0) swprintf_s(wbf, L"+%d", pd); else if (pd < 0) swprintf_s(wbf, L"-%d", -pd); } } break; case lRunnerTimeAfterDiff: if (r && pc && !invalidClass) { int tleg = r->tLeg >= 0 ? r->tLeg:0; if (r->getTotalStatus() == StatusOK && pc && !noTimingRunner()) { int after = r->getTotalRunningTime() - pc->getTotalLegLeaderTime(oClass::AllowRecompute::Yes, tleg, true, true); int afterOld = r->inputTime - pc->getBestInputTime(oClass::AllowRecompute::Yes, tleg); int ad = after - afterOld; if (ad > 0) swprintf_s(wbf, L"+%s", formatTimeMS(ad, false, mode).c_str()); if (ad < 0) wsptr = &formatTimeMS(ad, false, mode); } } break; case lRunnerRogainingPoint: if (r && !invalidClass) { if (pp.resultModuleIndex == -1) swprintf_s(wbf, L"%d", r->getRogainingPoints(true, false)); else swprintf_s(wbf, L"%d", r->getTempResult(pp.resultModuleIndex).getPoints()); } break; case lRunnerRogainingPointTotal: if (r && !invalidClass) { if (pp.resultModuleIndex == -1) swprintf_s(wbf, L"%d", r->getRogainingPoints(true, true)); else swprintf_s(wbf, L"%d", r->getTempResult(pp.resultModuleIndex).getPoints() + r->getInputPoints()); } break; case lRunnerRogainingPointReduction: if (r && !invalidClass) { int red = r->getRogainingReduction(true); if (red > 0) swprintf_s(wbf, L"-%d", red); } break; case lRunnerRogainingPointGross: if (r && !invalidClass) { int p = r->getRogainingPointsGross(true); wsptr = &itow(p); } break; case lRunnerPointAdjustment: if (r && !invalidClass) { int a = r->getPointAdjustment(); if (a<0) wsptr = &itow(a); else if (a>0) swprintf_s(wbf, L"+%d", a); } break; case lRunnerTimeAdjustment: if (r && !invalidClass) { int a = r->getTimeAdjustment(true); if (a != 0) wsptr = &formatTimeMS(a, false); } break; case lRunnerRogainingPointOvertime: if (r && !invalidClass) { int over = r->getRogainingOvertime(true); if (over > 0) wsptr = &formatTime(over); } break; case lRunnerTimeAfter: if (r && pc && !invalidClass && !noTimingRunner()) { int after = 0; if (pp.resultModuleIndex == -1) { int tleg=r->tLeg>=0 ? r->tLeg:0; int brt = pc->getBestLegTime(oClass::AllowRecompute::Yes, tleg, true); if (r->prelStatusOK(true, true, true) && brt > 0) { after=r->getRunningTime(true) - brt; } } else { after = r->getTempResult(pp.resultModuleIndex).getTimeAfter(); } if (r->getNumShortening() == 0) { if (after > 0) swprintf_s(wbf, L"+%s", formatTimeMS(after, false, mode).c_str()); } else { wsptr = &makeDash(L"-"); } } break; case lRunnerTotalTimeAfter: if (r && pc && !invalidClass) { int tleg = r->tLeg >= 0 ? r->tLeg:0; if (r->getTotalStatus()==StatusOK && pc && !noTimingRunner()) { if ( (t && t->getNumShortening(tleg) == 0) || (!t && r->getNumShortening() == 0)) { int after = r->getTotalRunningTime() - pc->getTotalLegLeaderTime(oClass::AllowRecompute::Yes, tleg, true, true); if (after > 0) swprintf_s(wbf, L"+%s", formatTimeMS(after, false, mode).c_str()); } else { wsptr = &makeDash(L"-"); } } } break; case lRunnerClassCourseTimeAfter: if (r && pc && !invalidClass) { pCourse crs = r->getCourse(false); if (crs && r->tStatus==StatusOK && !noTimingRunner()) { int after = r->getRunningTime(true) - pc->getBestTimeCourse(oClass::AllowRecompute::Yes, crs->getId()); if (after > 0) swprintf_s(wbf, L"+%s", formatTimeMS(after, false, mode).c_str()); } } break; case lRunnerTimePlaceFixed: if (r && !invalidClass) { int t = r->getTimeWhenPlaceFixed(); if (t == 0 || (t > 0 && t < getComputerTime())) { wcscpy_s(wbf, lang.tl("klar").c_str()); } else if (t == -1) wcscpy_s(wbf, L"-"); else wcscpy_s(wbf, oe->getAbsTime(t).c_str()); } break; case lRunnerLegNumberAlpha: case lRunnerLegNumber: if (r) return formatSpecialStringAux(pp, par, t, r->getLegNumber(), 0, 0, counter); else wcscpy_s(wbf, par.getLegName().c_str()); break; case lRunnerLostTime: if (r && r->prelStatusOK(true, true, true) && !noTimingRunner() && !invalidClass) { wcscpy_s(wbf, r->getMissedTimeS().c_str()); } break; case lRunnerTempTimeAfter: if (r && pc) { if (r->tempStatus == StatusOK && pc && !noTimingRunner() && r->tempRT > pc->tLegLeaderTime) { int after = r->tempRT - pc->tLegLeaderTime; swprintf_s(wbf, L"+%s", formatTimeMS(after, false, mode).c_str()); } } break; case lRunnerCard: if (r && r->getCardNo() > 0) swprintf_s(wbf, L"%d", r->getCardNo()); break; case lRunnerRank: if (r) { int rank = r->getRanking(); if (rank>0 && rank < MaxOrderRank) wcscpy_s(wbf, formatRank(rank).c_str()); } break; case lRunnerRankScore: if (r) { wcscpy_s(wbf, r->getRankingScore().c_str()); } break; case lRunnerBib: if (r) { const wstring &bib = r->getBib(); if (!bib.empty()) wsptr = &bib; } break; case lRunnerRentalCard: if (r && r->isRentalCard()) { wsptr = &lang.tl("Hyrd"); } break; case lRunnerUMMasterPoint: if (r) { int total, finished, dns; pc->getNumResults(par.getLegNumber(pc), total, finished, dns); int percent = int(floor(0.5+double((100*(total-dns-r->getPlace()))/double(total-dns)))); if (r->getStatus()==StatusOK) swprintf_s(wbf, L"%d", percent); else swprintf_s(wbf, L"0"); } break; case lRunnerAge: if (r) { int y = r->getBirthAge(); if (y > 0) swprintf_s(wbf, L"%d", y); } break; case lRunnerBirthYear: if (r) { int y = r->getBirthYear(); if (y > 0) swprintf_s(wbf, L"%d", y); } break; case lRunnerBirthDate: if (r) { wsptr = &r->getBirthDate(); } break; case lRunnerSex: if (r) { PersonSex s = r->getSex(); if (s == sFemale) wsptr = &lang.tl("Kvinna"); else if (s == sMale) wsptr = &lang.tl("Man"); } break; case lRunnerPhone: if (r) { wsptr = &r->getDCI().getString("Phone"); } break; case lRunnerFee: if (r) { wstring s = formatCurrency(r->getDCI().getInt("Fee")); wcscpy_s(wbf, s.c_str()); } break; case lRunnerExpectedFee: if (r) { wstring s = formatCurrency(r->getDefaultFee()); wcscpy_s(wbf, s.c_str()); } break; case lRunnerPaid: if (r) { wstring s = formatCurrency(r->getDCI().getInt("Paid")); wcscpy_s(wbf, s.c_str()); } break; case lRunnerId: if (r) { wstring s = r->getExtIdentifierString(); wcscpy_s(wbf, s.c_str()); } break; case lRunnerPayMethod: if (r) { wsptr = &r->getDCI().formatString(r, "PayMode"); } break; case lRunnerEntryDate: if (r && r->getDCI().getInt("EntryDate") > 0) { wsptr = &r->getDCI().getDate("EntryDate"); } break; case lRunnerEntryTime: if (r) { wsptr = &formatTime(r->getDCI().getInt("EntryTime")); } break; case lTeamFee: if (t) { wstring s = formatCurrency(t->getTeamFee()); wcscpy_s(wbf, s.c_str()); } break; case lRunnerNationality: if (r) { wstring nat = r->getNationality(); wcscpy_s(wbf, nat.c_str()); } break; case lTeamName: //sptr = t ? &t->Name : 0; if (t) { wcscpy_s(wbf, t->getDisplayName().c_str()); } break; case lTeamStart: case lTeamStartCond: case lTeamStartZero: if (t) { if ((pp.type == lTeamStartCond || pp.type == lTeamStartZero) && pc && !pc->hasFreeStart()) { int fs, ls; pc->getStartRange(legIndex, fs, ls); if (fs>0 && fs == ls) { break; // Common start time, skip } } if (unsigned(legIndex)Runners.size() && t->Runners[legIndex] && t->Runners[legIndex]->startTimeAvailable()) { if (pp.type != lTeamStartZero) wsptr = &t->Runners[legIndex]->getStartTimeCompact(); else { int st = t->Runners[legIndex]->getStartTime(); wsptr = &formatTimeMS(st-timeConstHour, true); } } } break; case lTeamStatus: if (t && !invalidClass) { if (pp.resultModuleIndex == -1) wsptr = &t->getLegStatusS(legIndex, true, false); else wsptr = &t->getTempResult(pp.resultModuleIndex).getStatusS(StatusOK); } break; case lTeamTime: if (t && !invalidClass) { if (pp.resultModuleIndex == -1) wcscpy_s(wbf, t->getLegRunningTimeS(legIndex, true, false, mode).c_str() ); else wsptr = &t->getTempResult(pp.resultModuleIndex).getRunningTimeS(0, mode); } break; case lTeamGrossTime: if (t && !invalidClass) { int tm = t->getLegRunningTimeUnadjusted(legIndex, false, false); wsptr = &formatTime(tm); } break; case lTeamTimeStatus: if (invalidClass) wsptr = &lang.tl("Struken"); else if (t) { if (pp.resultModuleIndex == -1) { RunnerStatus st = t->getLegStatus(legIndex, true, false); if (st == StatusOK || ((st == StatusUnknown || st == StatusOutOfCompetition) && t->getLegRunningTime(legIndex, true, false) > 0)) { if (st != StatusOutOfCompetition) wcscpy_s(wbf, t->getLegRunningTimeS(legIndex, true, false, mode).c_str()); else swprintf_s(wbf, L"(%s)", t->getLegRunningTimeS(legIndex, true, false, mode).c_str()); } else wsptr = &t->getLegStatusS(legIndex, true, false); } else { RunnerStatus st = t->getTempResult(pp.resultModuleIndex).getStatus(); if (st == StatusOK || st == StatusUnknown) { wsptr = &t->getTempResult(pp.resultModuleIndex).getRunningTimeS(0, mode); if (t->getNumShortening() > 0) { swprintf_s(wbf, L"*%s", wsptr->c_str()); wsptr = 0; } } else wsptr = &t->getTempResult(pp.resultModuleIndex).getStatusS(StatusOK); } } break; case lTeamRogainingPoint: if (t && !invalidClass) { if (pp.resultModuleIndex == -1) swprintf_s(wbf, L"%d", t->getRogainingPoints(true, false)); else swprintf_s(wbf, L"%d", t->getTempResult(pp.resultModuleIndex).getPoints()); } break; case lTeamRogainingPointTotal: if (t && !invalidClass) { if (pp.resultModuleIndex == -1) swprintf_s(wbf, L"%d", t->getRogainingPoints(true, true)); else swprintf_s(wbf, L"%d", t->getTempResult(pp.resultModuleIndex).getPoints() + t->getInputPoints()); } break; case lTeamRogainingPointReduction: if (t && !invalidClass) { int red = t->getRogainingReduction(true); if (red > 0) swprintf_s(wbf, L"-%d", red); } break; case lTeamRogainingPointOvertime: if (t && !invalidClass) { int over = t->getRogainingOvertime(true); if (over > 0) wsptr = &formatTime(over); } break; case lTeamPointAdjustment: if (t && !invalidClass) { int a = t->getPointAdjustment(); if (a<0) wsptr = &itow(a); else if (a>0) wprintf_s(wbf, "+%d", a); } break; case lTeamTimeAdjustment: if (t && !invalidClass) { int a = t->getTimeAdjustment(true); if (a != 0) wsptr = &formatTimeMS(a, false); } break; case lTeamTimeAfter: if (t && !invalidClass) { if (pp.resultModuleIndex == -1) { if (t->getLegStatus(legIndex, true, false)==StatusOK) { if (t->getNumShortening(legIndex) == 0) { int ta=t->getTimeAfter(legIndex, true); if (ta>0) swprintf_s(wbf, L"+%s", formatTimeMS(ta, false, mode).c_str()); } else { wsptr = &makeDash(L"-"); } } } else { if (t->getTempResult().getStatus() == StatusOK) { int after = t->getTempResult(pp.resultModuleIndex).getTimeAfter(); if (after > 0) swprintf_s(wbf, L"+%s", formatTimeMS(after, false, mode).c_str()); } } } break; case lTeamPlace: if (t && !invalidClass && !noTimingTeam() && pc && pc->isValidLeg(legIndex)) { if (pp.resultModuleIndex == -1) { wcscpy_s(wbf, t->getLegPrintPlaceS(legIndex, false, pp.text.empty()).c_str()); } else wsptr = &t->getTempResult(pp.resultModuleIndex).getPrintPlaceS(pp.text.empty()); } break; case lTeamLegTimeStatus: if (invalidClass) wsptr = &lang.tl("Struken"); else if (t) { /*int ix = r ? r->getLegNumber() : counter.level3; if (pc) ix = pc->getResultDefining(ix);*/ int ix = legIndex; if (pc) { if (!pc->isValidLeg(legIndex)) break; ix = pc->getResultDefining(ix); } RunnerStatus st = t->getLegStatus(ix, true, false); if (st == StatusOK) wcscpy_s(wbf, t->getLegRunningTimeS(ix, true, false, mode).c_str() ); else if (st == StatusOutOfCompetition && t->getLegRunningTime(ix, true, false) > 0) swprintf_s(wbf, L"(%s)", t->getLegRunningTimeS(ix, true, false, mode).c_str()); else wcscpy_s(wbf, t->getLegStatusS(ix, true, false).c_str() ); } break; case lTeamLegTimeAfter: if (t) { /*int ix = r ? r->getLegNumber() : counter.level3; xxx if (pc) ix = pc->getResultDefining(ix); */ int ix = legIndex; if (pc) { if (!pc->isValidLeg(legIndex)) break; ix = pc->getResultDefining(ix); } if (t->getLegStatus(ix, true, false)==StatusOK && !invalidClass) { if (t->getNumShortening(ix) == 0) { int ta=t->getTimeAfter(ix, true); if (ta>0) swprintf_s(wbf, L"+%s", formatTimeMS(ta, false, mode).c_str()); } else { wsptr = &makeDash(L"-"); } } } break; case lTeamClub: if (t) { wcscpy_s(wbf, t->getDisplayClub().c_str()); } break; case lTeamRunner: if (t && unsigned(legIndex)Runners.size() && t->Runners[legIndex]) wsptr=&t->Runners[legIndex]->getName(); break; case lTeamRunnerCard: if (t && unsigned(legIndex)Runners.size() && t->Runners[legIndex] && t->Runners[legIndex]->getCardNo()>0) swprintf_s(wbf, L"%d", t->Runners[legIndex]->getCardNo()); break; case lTeamBib: if (t) { wsptr = &t->getBib(); } break; case lTeamTotalTime: if (t && !invalidClass) wcscpy_s(wbf, t->getLegRunningTimeS(legIndex, true, true, mode).c_str() ); break; case lTeamTotalTimeStatus: if (invalidClass) wsptr = &lang.tl("Struken"); else if (t) { if (pp.resultModuleIndex == -1) { if (t->getLegStatus(legIndex, true, true)==StatusOK) wcscpy_s(wbf, t->getLegRunningTimeS(legIndex, true, true, mode).c_str() ); else wcscpy_s(wbf, t->getLegStatusS(legIndex, true, true).c_str() ); } else { RunnerStatus st = t->getTempResult(pp.resultModuleIndex).getStatus(); RunnerStatus inp = t->getInputStatus(); if (st == StatusOK && inp == StatusOK) { wsptr = &t->getTempResult(pp.resultModuleIndex).getRunningTimeS(0, mode); if (t->getNumShortening() > 0) { swprintf_s(wbf, L"*%s", wsptr->c_str()); wsptr = 0; } } else wsptr = &t->getTempResult(pp.resultModuleIndex).getStatusS(StatusOK); } } break; case lTeamPlaceDiff: if (t && !invalidClass) { int p = t->getTotalPlace(); if (t->getTotalStatus() == StatusOK && p > 0 && t->inputPlace>0) { int pd = p - t->inputPlace; if (pd > 0) swprintf_s(wbf, L"+%d", pd); else if (pd < 0) swprintf_s(wbf, L"-%d", -pd); } } break; case lTeamTotalPlace: if (t && !invalidClass && !noTimingTeam()) wcscpy_s(wbf, t->getPrintTotalPlaceS(pp.text.empty()).c_str() ); break; case lTeamTotalTimeAfter: if (t && pc && !invalidClass) { int tleg = t->getNumRunners() - 1; if (t->getTotalStatus()==StatusOK && pc && !noTimingTeam()) { int after = t->getTotalRunningTime() - pc->getTotalLegLeaderTime(oClass::AllowRecompute::Yes, tleg, true, true); if (after > 0) swprintf_s(wbf, L"+%s", formatTimeMS(after, false, mode).c_str()); } } break; case lTeamTotalTimeDiff: if (t && pc && !invalidClass) { int tleg = t->getNumRunners() - 1; if (t->getTotalStatus()==StatusOK && pc && !noTimingTeam()) { int after = t->getTotalRunningTime() - pc->getTotalLegLeaderTime(oClass::AllowRecompute::Yes, tleg, true, true); int afterOld = t->inputTime - pc->getBestInputTime(oClass::AllowRecompute::Yes, tleg); int ad = after - afterOld; if (ad > 0) swprintf_s(wbf, L"+%s", formatTimeMS(ad, false, mode).c_str()); if (ad < 0) wsptr = &formatTimeMS(ad, false, mode); } } break; case lTeamStartNo: if (t) swprintf_s(wbf, L"%d", t->getStartNo()); break; case lRunnerStartNo: if (r) swprintf_s(wbf, L"%d", r->getStartNo()); break; case lRunnerDataA: if (r) wsptr = &itow(r->getDCI().getInt("DataA")); break; case lRunnerDataB: if (r) wsptr = &itow(r->getDCI().getInt("DataB")); break; case lRunnerTextA: if (r) wsptr = &r->getDCI().getString("TextA"); break; case lTeamDataA: if (t) wsptr = &itow(t->getDCI().getInt("DataA")); break; case lTeamDataB: if (t) wsptr = &itow(t->getDCI().getInt("DataB")); break; case lTeamTextA: if (t) wsptr = &t->getDCI().getString("TextA"); break; case lNationality: if (r && !(wsptr = &r->getDCI().getString("Nationality"))->empty()) break; else if (t && !(wsptr = &t->getDCI().getString("Nationality"))->empty()) break; else if (c && !(wsptr = &c->getDCI().getString("Nationality"))->empty()) break; break; case lCountry: if (r && !(wsptr = &r->getDCI().getString("Country"))->empty()) break; else if (t && !(wsptr = &t->getDCI().getString("Country"))->empty()) break; else if (c && !(wsptr = &c->getDCI().getString("Country"))->empty()) break; break; case lControlName: case lPunchName: case lPunchNamedTime: case lPunchTeamTotalNamedTime: case lPunchNamedSplit: case lPunchTime: case lPunchTeamTime: case lPunchSplitTime: case lPunchTotalTime: case lPunchTeamTotalTime: case lPunchControlNumber: case lPunchControlCode: case lPunchLostTime: case lPunchControlPlace: case lPunchControlPlaceAcc: case lPunchControlPlaceTeamAcc: case lPunchAbsTime: case lPunchTotalTimeAfter: case lPunchTeamTotalTimeAfter: if (r && r->getCourse(false) && !invalidClass) { const pCourse crs=r->getCourse(true); const oControl *ctrl = nullptr; int nCtrl = crs->getNumControls(); if (counter.level3 != nCtrl) { // Always allow finish ctrl=crs->getControl(counter.level3); if (!ctrl || ctrl->isRogaining(crs->hasRogaining())) break; } switch (pp.type) { case lPunchNamedSplit: if (ctrl && ctrl->hasName() && r->getPunchTime(counter.level3, false, true, false) > 0) { swprintf_s(wbf, L"%s", r->getNamedSplitS(counter.level3, SubSecond::Off).c_str()); } break; case lPunchNamedTime: case lPunchTeamTotalNamedTime: if (ctrl && ctrl->hasName() && (!par.lineBreakControlList || r->getPunchTime(counter.level3, false, true, false) > 0)) { swprintf_s(wbf, L"%s: %s (%s)", ctrl->getName().c_str(), r->getPunchTimeS(counter.level3, false, true, pp.type == lPunchTeamTotalNamedTime, SubSecond::Off).c_str(), r->getNamedSplitS(counter.level3, SubSecond::Off).c_str()); } break; case lControlName: case lPunchName: if (ctrl && ctrl->hasName() && (!par.lineBreakControlList || r->getPunchTime(counter.level3, false, true, false) > 0)) { swprintf_s(wbf, L"%s", ctrl->getName().c_str()); } else if (counter.level3 == nCtrl) { wsptr = &lang.tl(L"Mål"); } break; case lPunchTime: case lPunchTeamTime: { swprintf_s(wbf, L"%s (%s)", r->getSplitTimeS(counter.level3, false, SubSecond::Off).c_str(), r->getPunchTimeS(counter.level3, false, true, pp.type == lPunchTeamTime, SubSecond::Off).c_str()); break; } case lPunchSplitTime: { wcscpy_s(wbf, r->getSplitTimeS(counter.level3, false, SubSecond::Off).c_str()); break; } case lPunchTotalTime: case lPunchTeamTotalTime: { int pt = r->getPunchTime(counter.level3, false, true, pp.type == lPunchTeamTotalTime); if (pt > 0) wsptr = &formatTime(pt, SubSecond::Off); break; } case lPunchTotalTimeAfter: case lPunchTeamTotalTimeAfter: { if (r->getPunchTime(counter.level3, false, true, false) > 0) { int rt = r->getLegTimeAfterAcc(counter.level3, pp.type == lPunchTeamTotalTimeAfter); if (rt > 0) wcscpy_s(wbf, (L"+" + formatTime(rt, SubSecond::Off)).c_str()); } break; } case lPunchControlNumber: { wcscpy_s(wbf, crs->getControlOrdinal(counter.level3).c_str()); break; } case lPunchControlCode: { const oControl *ctrl = crs->getControl(counter.level3); if (ctrl) { if (ctrl->getStatus() == oControl::ControlStatus::StatusMultiple) { wstring str = ctrl->getStatusS(); swprintf_s(wbf, L"%s.", str.substr(0, 1).c_str()); } else swprintf_s(wbf, L"%d", ctrl->getFirstNumber()); } break; } case lPunchControlPlace: { int p = r->getLegPlace(counter.level3); if (p > 0) swprintf_s(wbf, L"%d", p); break; } case lPunchControlPlaceAcc: case lPunchControlPlaceTeamAcc: { int p = r->getLegPlaceAcc(counter.level3, pp.type == lPunchControlPlaceTeamAcc); if (p > 0) swprintf_s(wbf, L"%d", p); break; } case lPunchLostTime: { wcscpy_s(wbf, r->getMissedTimeS(counter.level3).c_str()); break; } case lPunchAbsTime: { int t = r->getPunchTime(counter.level3, false, true, false); if (t > 0) wsptr = &getAbsTime(r->tStartTime + t); break; } } } break; case lSubSubCounter: if (pp.text.empty()) swprintf_s(wbf, L"%d.", counter.level3+1); else swprintf_s(wbf, L"%d", counter.level3+1); break; case lSubCounter: if (pp.text.empty()) swprintf_s(wbf, L"%d.", counter.level2+1); else swprintf_s(wbf, L"%d", counter.level2+1); break; case lTotalCounter: if (pp.text.empty()) swprintf_s(wbf, L"%d.", counter.level1+1); else swprintf_s(wbf, L"%d", counter.level1+1); break; case lTotalRunLength: { int sum = 0; for (auto& r : Runners) { if (!r.isRemoved() && r.getCourse(false) && r.isStatusOK(false, false)) sum += r.getCourse(false)->getLength(); } wsptr = &itow(sum/1000); break; } case lTotalRunTime: { int sum = 0; for (auto& r : Runners) { if (!r.isRemoved()) sum += r.getRunningTime(false); } wsptr = &formatTimeHMS(sum); break; } case lNumEntries: { int sum = 0; for (auto& r : Runners) { if (!r.isRemoved() && r.tParentRunner == nullptr) sum++; } wsptr = &itow(sum); break; } case lNumStarts: { int sum = 0; for (auto& r : Runners) { if (!r.isRemoved() && r.tParentRunner == nullptr && (oAbstractRunner::isResultStatus(r.getStatus()) || r.isStatusOK(false, false))) sum++; } wsptr = &itow(sum); break; } case lClubName: wsptr = c != 0 ? &c->getDisplayName() : 0; break; case lResultModuleTime: case lResultModuleTimeTeam: if (pp.resultModuleIndex != -1) { if (t && pp.type == lResultModuleTimeTeam) wsptr = &t->getTempResult(pp.resultModuleIndex).getOutputTime(legIndex); else if (r) wsptr = &r->getTempResult(pp.resultModuleIndex).getOutputTime(legIndex); } break; case lResultModuleNumber: case lResultModuleNumberTeam: if (pp.resultModuleIndex != -1) { int nr = 0; if (t && pp.type == lResultModuleNumberTeam) nr = t->getTempResult(pp.resultModuleIndex).getOutputNumber(legIndex); else if (r) nr = r->getTempResult(pp.resultModuleIndex).getOutputNumber(legIndex); if (pp.text.empty() || pp.text[0]!='@') wsptr = &itow(nr); else { wstring &res = StringCache::getInstance().wget(); MetaList::fromResultModuleNumber(pp.text.substr(1), nr, res); return res; } } break; case lRogainingPunch: if (r && r->Card && r->getCourse(false)) { const pCourse crs = r->getCourse(false); const pPunch punch = r->Card->getPunchByIndex(counter.level3); if (punch && punch->tRogainingIndex>=0) { const pControl ctrl = crs->getControl(punch->tRogainingIndex); if (ctrl) { swprintf_s(wbf, L"%d, %dp, %s (%s)", punch->type, ctrl->getRogainingPoints(), r->Card->getRogainingSplit(counter.level3, r->tStartTime).c_str(), punch->getRunningTime(r->tStartTime).c_str()); } } } break; case lLineBreak: break; } if (pp.type!=lString && (wsptr==0 || wsptr->empty()) && wbf[0]==0) return _EmptyWString; else if (wsptr) { if (pp.text.empty()) return *wsptr; else { swprintf_s(wbf, pp.text.c_str(), wsptr->c_str()); wstring &res = StringCache::getInstance().wget(); res = wbf; return res; } } else { if (pp.text.empty()) { wstring &res = StringCache::getInstance().wget(); res = wbf; return res; } else { wchar_t bf2[512]; swprintf_s(bf2, pp.text.c_str(), wbf); wstring &res = StringCache::getInstance().wget(); res = bf2; return res; } } } bool oEvent::formatPrintPost(const list &ppli, PrintPostInfo &ppi, const pTeam t, const pRunner r, const pClub c, const pClass pc, const pCourse crs, const pControl ctrl, const oPunch *punch, int legIndex) { int y = ppi.gdi.getCY(); int x = ppi.gdi.getCX(); bool updated = false; int lineHeight = 0; int pdx = 0, pdy = 0; auto ppit = ppli.begin(); while (ppit != ppli.end()) { const oPrintPost &pp = *ppit; if (pp.type == lLineBreak) { x -= ppi.gdi.scaleLength(pp.dx) - pdx; pdx = ppi.gdi.scaleLength(pp.dx); y += lineHeight; ++ppit; continue; } else if (pp.type == lImage) { pdy = ppi.gdi.scaleLength(pp.dy); pdx = ppi.gdi.scaleLength(pp.dx); int format = 0; if (pp.imageNoUpdatePos) format |= imageNoUpdatePos; ppi.gdi.addImage("", y + pdy, x + pdx, format, pp.text, ppi.gdi.scaleLength(pp.fixedWidth), ppi.gdi.scaleLength(pp.fixedHeight)); ++ppit; continue; } int limit = ppit->xlimit; bool keepNext = false; //Skip merged entities while (ppit != ppli.end() && ppit->doMergeNext) ++ppit; // Main increment below if (++ppit != ppli.end() && ppit->dy == pp.dy) limit = ppit->dx - pp.dx; else keepNext = true; if (pp.useStrictWidth) limit = max(pp.fixedWidth - 5, 0); // Allow some space else limit = max(pp.fixedWidth, limit); assert(limit >= 0); pRunner rr = r; if (!rr && t) { if (pp.legIndex >= 0) { if (pc) { int lg = pp.legIndex; if (pp.legIndex < max(1, pc->getNumStages())) lg = pc->getLinearIndex(pp.legIndex, pp.linearLegIndex); rr = t->getRunner(lg); } } else if (legIndex >= 0) rr = t->getRunner(legIndex); else { int lg = ppi.par.getLegNumber(pc); rr = t->getRunner(lg); } } const wstring &text = punch ? formatPunchString(pp, ppi.par, t, rr, punch, ppi.counter) : ((legIndex == -1) ? formatListString(pp, ppi.par, t, rr, c, pc, ppi.counter) : formatSpecialString(pp, ppi.par, t, legIndex, crs, ctrl, ppi.counter)); updated |= !text.empty(); TextInfo *ti = 0; if (!text.empty()) { int tightBBFlag = ppi.par.tightBoundingBox ? 0 : skipBoundingBox; pdy = ppi.gdi.scaleLength(pp.dy); pdx = ppi.gdi.scaleLength(pp.dx); if ((pp.type == lRunnerName || pp.type == lRunnerCompleteName || pp.type == lRunnerFamilyName || pp.type == lRunnerGivenName || pp.type == lTeamRunner || (pp.type == lPatrolNameNames && !t)) && rr) { ti = &ppi.gdi.addStringUT(y + pdy, x + pdx, pp.format | tightBBFlag, text, ppi.gdi.scaleLength(limit), ppi.par.cb, pp.fontFace.c_str()); ti->setExtra(rr->getId()); ti->id = "R"; } else if ((pp.type == lTeamName || pp.type == lPatrolNameNames) && t) { ti = &ppi.gdi.addStringUT(y + pdy, x + pdx, pp.format | tightBBFlag, text, ppi.gdi.scaleLength(limit), ppi.par.cb, pp.fontFace.c_str()); ti->setExtra(t->getId()); ti->id = "T"; } else { ti = &ppi.gdi.addStringUT(y + pdy, x + pdx, pp.format | tightBBFlag, text, ppi.gdi.scaleLength(limit), 0, pp.fontFace.c_str()); } if (ti && ppi.keepToghether) ti->lineBreakPrioity = -1; if (ti) { lineHeight = ti->getHeight(); } if (pp.color != colorDefault) ti->setColor(pp.color); } ppi.keepToghether |= keepNext; } return updated; } void oEvent::calculatePrintPostKey(const list &ppli, gdioutput &gdi, const oListParam &par, const pTeam t, const pRunner r, const pClub c, const pClass pc, oCounter &counter, wstring &key) { key.clear(); list::const_iterator ppit; for (ppit=ppli.begin();ppit!=ppli.end(); ++ppit) { const oPrintPost &pp=*ppit; pRunner rr = r; if (!rr && t) { int linLeg = pp.legIndex; if (pc) linLeg = pc->getLinearIndex(pp.legIndex, pp.linearLegIndex); rr=t->getRunner(linLeg); } const wstring &text = formatListString(pp, par, t, rr, c, pc, counter); key += text; //Skip merged entities while (ppit != ppli.end() && ppit->doMergeNext) ++ppit; } } void oEvent::listGeneratePunches(const oListInfo &listInfo, gdioutput &gdi, pTeam t, pRunner r, pClub club, pClass cls) { const list &ppli = listInfo.subListPost; const oListParam &par = listInfo.lp; auto type = listInfo.listSubType; if (!r || ppli.empty()) return; bool filterNamed = listInfo.subFilter(ESubFilterNamedControl); const bool filterFinish = listInfo.subFilter(ESubFilterNotFinish); pCourse crs = r->getCourse(true); if (cls && cls->getNoTiming()) return; if (r && (r->getStatusComputed(true) == StatusNoTiming || r->noTiming())) return; int h = gdi.getLineHeight(); int w = 0; bool newLine = false; int haccum = 0; for (auto &pl : ppli) { if (pl.type == lPunchNamedTime) filterNamed = true; if (pl.type == lLineBreak) { haccum += h; h = 0; newLine = true; continue; } h = max(h, gdi.getLineHeight(pl.getFont(), pl.fontFace.c_str()) + gdi.scaleLength(pl.dy)); w = max(w, gdi.scaleLength(pl.fixedWidth + pl.dx)); } h += haccum; int xlimit = gdi.getCX() + gdi.scaleLength(600); par.lineBreakControlList = newLine; // Controls if controls names are printed even if the runner has not punched there yet. if (w > 0) { gdi.pushX(); gdi.fillNone(); } bool neednewline = false; bool updated = false; int limit = crs ? crs->nControls + 1 : 1; if (r->Card && r->Card->getNumPunches() > limit) limit = r->Card->getNumPunches(); vector skip(limit, false); if (filterNamed && crs) { for (int k = 0; k < crs->nControls; k++) { if (crs->getControl(k) && !crs->getControl(k)->hasName()) skip[k] = true; } for (int k = crs->nControls + 1; k < limit; k++) { skip[k] = true; } if (filterFinish) skip[crs->nControls] = true; } bool filterRadioTimes = listInfo.sortOrder == SortOrder::ClassLiveResult || listInfo.filter(EFilterList::EFilterAnyResult); if (filterRadioTimes && crs) { for (int k = 0; k < crs->nControls; k++) { if (crs->getControl(k) && !crs->getControl(k)->isValidRadio()) skip[k] = true; } for (int k = crs->nControls + 1; k < limit; k++) { skip[k] = true; } if (filterFinish) skip[crs->nControls] = true; } PrintPostInfo ppi(gdi, par); if (type == oListInfo::EBaseType::EBaseTypeCoursePunches) { for (int k = 0; k < limit; k++) { if (w > 0 && updated) { updated = false; if (gdi.getCX() + w > xlimit || newLine) { neednewline = false; gdi.popX(); gdi.setCY(gdi.getCY() + h); } else gdi.setCX(gdi.getCX() + w); } if (!skip[k]) { updated |= formatPrintPost(ppli, ppi, t, r, club, cls, nullptr, nullptr, nullptr, -1); neednewline |= updated; } ppi.counter.level3++; } } else if(type == oListInfo::EBaseType::EBaseTypeAllPunches) { int startType = -1; int finishType = -1; const pCourse pcrs = r->getCourse(false); if (pcrs) { startType = pcrs->getStartPunchType(); finishType = pcrs->getFinishPunchType(); } int prevPunchTime = r->getStartTime(); vector punches; if (r->Card) { for (auto &punch : r->Card->punches) punches.push_back(&punch); } else { vector fPunches; oe->getPunchesForRunner(r->getId(), true, fPunches); for (auto punch : fPunches) punches.push_back(punch); } for (auto &pPunch : punches) { const oPunch &punch = *pPunch; punch.previousPunchTime = prevPunchTime; if (punch.isCheck() || punch.isStart(startType)) continue; if (filterFinish && punch.isFinish(finishType)) continue; prevPunchTime = punch.getTimeInt(); if (w > 0 && updated) { updated = false; if (gdi.getCX() + w > xlimit || newLine) { neednewline = false; gdi.popX(); gdi.setCY(gdi.getCY() + h); } else gdi.setCX(gdi.getCX() + w); } updated |= formatPrintPost(ppli, ppi, t, r, club, cls, nullptr, nullptr, &punch, -1); neednewline |= updated; ppi.counter.level3++; } } if (w > 0) { gdi.popX(); gdi.fillDown(); if (neednewline) gdi.setCY(gdi.getCY() + h); } } void oEvent::generateList(gdioutput &gdi, bool reEvaluate, const oListInfo &li, bool updateScrollBars) { if (reEvaluate) reEvaluateAll(set(), false); oe->calcUseStartSeconds(); oe->calculateNumRemainingMaps(false); oe->updateComputerTime(); oe->setGeneralResultContext(&li.lp); wstring listname; if (!li.head.empty()) { oCounter counter; const wstring &name = formatListString(li.head.front(), li.lp, 0, 0, 0, 0, counter); listname = name; li.lp.updateDefaultName(name); } bool addHead = li.lp.showHeader && !li.lp.useLargeSize; size_t nClassesSelected = li.lp.selection.size(); if (nClassesSelected!=0 && nClassesSelected < min(Classes.size(), Classes.size()/2+5) ) { // Non-trivial class selection: Classes.sort(); wstring cls; for (oClassList::iterator it = Classes.begin(); it != Classes.end(); ++it) { if (li.lp.selection.count(it->getId())) { cls += makeDash(L" - "); cls += it->getName(); } } listname += cls; } if (li.lp.getLegNumberCoded() != -1) { listname += lang.tl(L" Sträcka X#" + li.lp.getLegName()); } generateListInternal(gdi, li, addHead); for (list::const_iterator it = li.next.begin(); it != li.next.end(); ++it) { bool interHead = addHead && it->getParam().showInterTitle; if (li.lp.pageBreak || it->lp.pageBreak) { gdi.dropLine(1.0); gdi.addStringUT(gdi.getCY() - 1, 0, pageNewPage, ""); } else if (interHead) { gdi.dropLine(1.5); gdi.addStringUT(gdi.getCY() - 1, 0, pageNewChapter, ""); } else { gdi.addStringUT(gdi.getCY() - 1, 0, pageNewPage, ""); } generateListInternal(gdi, *it, interHead); } // Reset context oe->setGeneralResultContext(nullptr); gdi.setListDescription(listname); if (updateScrollBars) gdi.updateScrollbars(); } bool oListInfo::filterRunner(const oRunner &r) const { if (r.isRemoved()) return true; if (r.tStatus == StatusNotCompetiting && !filter(EFilterIncludeNotParticipating)) return true; if (!lp.selection.empty() && lp.selection.count(r.getClassId(true)) == 0) return true; if (!lp.matchLegNumber(r.getClassRef(false), r.legToRun())) return true; if (lp.ageFilter != oListParam::AgeFilter::All) { int age = r.getBirthAge(); if (age > 0) { oDataConstInterface odc = r.getEvent()->getDCI(); int lowAgeLimit = odc.getInt("YouthAge"); //int highAgeLimit = odc.getInt("SeniorAge"); if (lp.ageFilter == oListParam::AgeFilter::ExludeYouth && age <= lowAgeLimit) return true; if (lp.ageFilter == oListParam::AgeFilter::OnlyYouth && age > lowAgeLimit) return true; } else { // Consider "normal" if (lp.ageFilter != oListParam::AgeFilter::ExludeYouth) return true; } } if (filter(EFilterExcludeDNS)) { if (r.tStatus == StatusDNS) return true; if (r.Class && r.Class->isQualificationFinalBaseClass()) { if (r.getLegNumber() > 0 && r.getClassRef(true) == r.Class) return true; //Not qualified -> out } } if (filter(EFilterExcludeCANCEL) && r.tStatus == StatusCANCEL) return true; if (filter(EFilterVacant)) { if (r.isVacant()) return true; } if (filter(EFilterOnlyVacant)) { if (!r.isVacant()) return true; } if (filter(EFilterAnyResult)) { if (!r.hasOnCourseResult()) return true; } if (filter(EFilterAPIEntry)) { if (!r.hasFlag(oRunner::FlagAddedViaAPI)) return true; } if (filter(EFilterWrongFee)) { if (r.getEntryFee() == r.getDefaultFee()) return true; } if (filter(EFilterModifiedCard)) { if (!r.getCard() || r.getCard()->isOriginalCard() != oCard::PunchOrigin::Manual) return true; } if (filter(EFilterRentCard) && !r.isRentalCard()) return true; if (filter(EFilterHasCard) && r.getCardNo() == 0) return true; if (filter(EFilterHasNoCard) && r.getCardNo() > 0) return true; return false; } bool oListInfo::filterRunnerResult(GeneralResult *gResult, const oRunner &r) const { if (gResult && r.getTempResult(0).getStatus() == StatusNotCompetiting) return true; if (filter(EFilterHasResult)) { if (gResult == 0) { if (lp.useControlIdResultTo <= 0 && !r.hasResult()) return true; else if ((lp.useControlIdResultTo > 0 || lp.useControlIdResultFrom > 0) && r.tempStatus != StatusOK) return true; else if (calcTotalResults && r.getTotalStatus() == StatusUnknown) return true; } else { auto &res = r.getTempResult(0); RunnerStatus st = res.getStatus(); if (st == StatusUnknown || isPossibleResultStatus(st) && r.getRunningTime(false) <= 0) return true; } } else if (filter(EFilterHasPrelResult)) { if (gResult == 0) { if (lp.useControlIdResultTo <= 0 && (r.tStatus == StatusUnknown || isPossibleResultStatus(r.getStatusComputed(true))) && r.getRunningTime(false) <= 0) return true; else if ((lp.useControlIdResultTo > 0 || lp.useControlIdResultFrom > 0) && r.tempStatus != StatusOK) return true; else if (calcTotalResults && r.getTotalStatus() == StatusUnknown && r.getTotalRunningTime() <= 0) return true; } else { auto &res = r.getTempResult(0); int rt = res.getRunningTime(); RunnerStatus st = res.getStatus(); if ((st == StatusUnknown || isPossibleResultStatus(st)) && rt <= 0) return true; } } return false; } GeneralResult *oListInfo::applyResultModule(oEvent &oe, vector &rlist) const { GeneralResult *gResult = nullptr; if (!resultModule.empty()) { wstring src; oListInfo::ResultType resType = getResultType(); gResult = oe.getGeneralResult(resultModule, src).get(); gResult->calculateIndividualResults(rlist, false, resType, sortOrder == Custom, getParam().getInputNumber()); if (sortOrder == SortByFinishTime || sortOrder == SortByFinishTimeReverse || sortOrder == SortByStartTime) gResult->sort(rlist, sortOrder); } return gResult; } void oEvent::formatHeader(gdioutput& gdi, const oListInfo& li, const pRunner rInput) { vector< pair > v; int* xLimitForwardUpdate = nullptr; for (auto& lp : li.head) { bool strUpdate = lp.type == lCmpName || lp.type == lString; if (lp.xlimit == 0 && !strUpdate) { v.clear(); v.emplace_back(lp.type, lp.text); gdiFonts font = lp.getFont(); lp.xlimit = li.getMaxCharWidth(this, gdi, li.getParam().selection, v, font, lp.fontFace.c_str()); } else if (strUpdate) { v.clear(); const_cast(lp.text) = li.lp.getCustomTitle(lp.text); v.emplace_back(lp.type, lp.text); gdiFonts font = lp.getFont(); lp.xlimit = li.getMaxCharWidth(this, gdi, li.getParam().selection, v, font, lp.fontFace.c_str()); } if (xLimitForwardUpdate) (*xLimitForwardUpdate) += lp.xlimit; if (lp.doMergeNext && xLimitForwardUpdate == nullptr) xLimitForwardUpdate = &lp.xlimit; else xLimitForwardUpdate = nullptr; } pTeam team = nullptr; pClass cls = nullptr; pClub club = nullptr; pCourse crs = nullptr; int legIndex = -1; if (rInput) { team = rInput->getTeam(); club = rInput->getClubRef(); crs = rInput->getCourse(true); cls = rInput->getClassRef(true); } PrintPostInfo printPostInfo(gdi, li.lp); formatPrintPost(li.head, printPostInfo, team, rInput, club, cls, crs, nullptr, nullptr, -1); } void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool formatHead) { li.setupLinks(); pClass sampleClass = 0; bool calculatedSplitResults = false; if (!li.lp.selection.empty()) sampleClass = getClass(*li.lp.selection.begin()); if (!sampleClass && !Classes.empty()) sampleClass = &*Classes.begin(); if (li.listType == li.EBaseTypeRunner) { if (li.calculateLiveResults || li.sortOrder == SortOrder::ClassLiveResult) calculateResults(li.lp.selection, ResultType::PreliminarySplitResults); if (li.calcCourseClassResults) calculateResults(li.lp.selection, ResultType::ClassCourseResult); if (li.calcCourseResults) calculateResults(li.lp.selection, ResultType::CourseResult); if (li.calcTotalResults) { calculateTeamResults(li.lp.selection, ResultType::TotalResult); calculateResults(li.lp.selection, ResultType::TotalResult); } if (li.calcResults) { if (li.lp.useControlIdResultTo > 0 || li.lp.useControlIdResultFrom > 0) { calculateSplitResults(li.lp.useControlIdResultFrom, li.lp.useControlIdResultTo); calculatedSplitResults = true; } else { calculateTeamResults(li.lp.selection, ResultType::ClassResult); calculateResults(li.lp.selection, ResultType::ClassResult); } } } else if (li.listType == li.EBaseTypeTeam || li.listType == li.EBaseTypeClubTeam) { if (li.calcResults) calculateTeamResults(li.lp.selection, ResultType::ClassResult); if (li.calcTotalResults) calculateTeamResults(li.lp.selection, ResultType::TotalResult); if (li.calcCourseResults) calculateTeamResults(li.lp.selection, ResultType::CourseResult); if (li.calculateLiveResults || li.sortOrder == SortOrder::ClassLiveResult) calculateResults(li.lp.selection, ResultType::PreliminarySplitResults); if (li.calcCourseClassResults) calculateResults(li.lp.selection, ResultType::ClassCourseResult); } else if (li.listType == li.EBaseTypeClubRunner) { if (li.calcResults) { calculateTeamResults(li.lp.selection, ResultType::TotalResult); calculateTeamResults(li.lp.selection, ResultType::ClassResult); } if (li.calcCourseClassResults) calculateResults(li.lp.selection, ResultType::ClassCourseResult); if (li.calcCourseResults) calculateResults(li.lp.selection, ResultType::CourseResult); if (li.calcResults) { if (li.lp.useControlIdResultTo > 0 || li.lp.useControlIdResultFrom > 0) { calculateSplitResults(li.lp.useControlIdResultFrom, li.lp.useControlIdResultTo); calculatedSplitResults = true; } else { calculateResults(li.lp.selection, ResultType::ClassResult); } } } PrintPostInfo printPostInfo(gdi, li.lp); //oCounter counter; //Render header vector< pair > v; for (auto &listPostList : { &li.subHead, &li.listPost, &li.subListPost }) { for (auto &lp : *listPostList) { if (lp.xlimit == 0) { v.clear(); v.emplace_back(lp.type, lp.text); gdiFonts font = lp.getFont(); lp.xlimit = li.getMaxCharWidth(this, gdi, li.getParam().selection, v, font, lp.fontFace.c_str()); } } } if (formatHead && li.getParam().showHeader) formatHeader(gdi, li, nullptr); if (li.fixedType) { generateFixedList(gdi, li); return; } // Apply for all teams (calculate start times etc.) vector tlist; tlist.reserve(Teams.size()); const bool include_nc = li.filter(EFilterIncludeNotParticipating); for (oTeamList::iterator it = Teams.begin(); it != Teams.end(); ++it) { if (it->isRemoved() || (!include_nc && it->tStatus == StatusNotCompetiting)) continue; if (!li.lp.selection.empty() && li.lp.selection.count(it->getClassId(true)) == 0) continue; it->apply(oBase::ChangeType::Quiet, nullptr); tlist.push_back(&*it); } vector rlist; GeneralResult *gResult = nullptr; if (li.listType == li.EBaseTypeRunner || li.listType == li.EBaseTypeClubRunner) { vector rlistInput; getRunners(li.lp.selection, rlistInput, false); rlist.reserve(rlistInput.size()); for (auto r : rlistInput) { if (!li.filterRunner(*r)) rlist.push_back(r); } if (li.sortOrder != Custom && !calculatedSplitResults) sortRunners(li.sortOrder, rlist); gResult = li.applyResultModule(*this, rlist); } wstring oldKey; auto formatTeam = [this, &gdi, &li, &gResult, &printPostInfo, &oldKey](pTeam it, bool includeSubHead, int &parLegRangeMin, int &parLegRangeMax, pClass &parLegRangeClass) { int linearLegSpec = li.lp.getLegNumber(it->getClassRef(false)); if (gResult && it->getTempResult(0).getStatus() == StatusNotCompetiting && !li.filter(EFilterIncludeNotParticipating)) return false; if (li.filter(EFilterExcludeDNS)) { if (it->tStatus == StatusDNS) return false; } if (li.filter(EFilterVacant)) { if (it->isVacant()) return false; } if (li.filter(EFilterOnlyVacant)) { if (!it->isVacant()) return false; } if (li.filter(EFilterModifiedCard)) { bool modified = false; for (pRunner r : it->Runners) { if (r && r->getCard() && r->getCard()->isOriginalCard() == oCard::PunchOrigin::Manual) modified = true; } if (modified) return false; } if (li.filter(EFilterHasResult)) { if (gResult) { RunnerStatus st = it->getTempResult(0).getStatus(); if (st == StatusUnknown || (isPossibleResultStatus(st) && it->getTempResult(0).getRunningTime() <= 0)) return false; } else { RunnerStatus st = it->getLegStatus(linearLegSpec, true, false); if (st == StatusUnknown || (isPossibleResultStatus(st) && it->getLegRunningTime(linearLegSpec, true, false) <= 0)) return false; else if (li.calcTotalResults) { st = it->getLegStatus(linearLegSpec, true, true); if (st == StatusUnknown || (isPossibleResultStatus(st) && it->getLegRunningTime(linearLegSpec, true, true) <= 0)) return false; } } } else if (li.filter(EFilterHasPrelResult)) { if (gResult) { RunnerStatus st = it->getTempResult(0).getStatus(); if ((st == StatusUnknown || isPossibleResultStatus(st)) && it->getTempResult(0).getRunningTime() <= 0) return false; } else { RunnerStatus st = it->getLegStatus(linearLegSpec, true, false); if ((st == StatusUnknown || isPossibleResultStatus(st)) && it->getLegRunningTime(linearLegSpec, true, false) <= 0) return false; else if (li.calcTotalResults) { RunnerStatus st = it->getLegStatus(linearLegSpec, true, true); if ((st == StatusUnknown || isPossibleResultStatus(st)) && it->getLegRunningTime(linearLegSpec, true, true) <= 0) return false; } } } else if (li.filter(EFilterAnyResult)) { pRunner r = it->getRunner(linearLegSpec); if (!r || !r->hasOnCourseResult()) return false; } const bool needParRange = li.subFilter(ESubFilterSameParallel) || li.subFilter(ESubFilterSameParallelNotFirst); if (needParRange && it->Class != parLegRangeClass && it->Class) { parLegRangeClass = it->Class; parLegRangeClass->getParallelRange(linearLegSpec < 0 ? 0 : linearLegSpec, parLegRangeMin, parLegRangeMax); if (li.subFilter(ESubFilterSameParallelNotFirst)) parLegRangeMin++; } if (includeSubHead) { wstring newKey; printPostInfo.par.relayLegIndex = linearLegSpec; calculatePrintPostKey(li.subHead, gdi, li.lp, &*it, 0, it->Club, it->Class, printPostInfo.counter, newKey); if (newKey != oldKey) { if (!oldKey.empty()) gdi.addStringUT(gdi.getCY() - 1, 0, pageNewPage, ""); wstring legInfo; if (linearLegSpec >= 0 && it->getClassRef(false)) { // Specified leg legInfo = lang.tl(L", Str. X#" + li.lp.getLegName()); } gdi.addStringUT(pagePageInfo, it->getClass(true) + legInfo); // Teamlist oldKey.swap(newKey); printPostInfo.counter.level2 = 0; printPostInfo.counter.level3 = 0; printPostInfo.reset(); printPostInfo.par.relayLegIndex = linearLegSpec; formatPrintPost(li.subHead, printPostInfo, &*it, 0, it->Club, it->Class, nullptr, nullptr, nullptr, -1); } } ++printPostInfo.counter; if (li.lp.filterInclude(printPostInfo.counter.level2, it)) { printPostInfo.counter.level3 = 0; printPostInfo.reset(); printPostInfo.par.relayLegIndex = linearLegSpec; formatPrintPost(li.listPost, printPostInfo, it, 0, it->Club, it->Class, nullptr, nullptr, nullptr, -1); if (li.subListPost.empty()) return true; if (li.listSubType == li.EBaseTypeRunner) { int nr = int(it->Runners.size()); vector tr; tr.reserve(nr); vector usedIx(nr, -1); for (int k = 0; k < nr; k++) { if (!it->Runners[k]) { if (li.filter(EFilterHasResult) || li.subFilter(ESubFilterHasResult) || li.filter(EFilterHasPrelResult) || li.subFilter(ESubFilterHasPrelResult) || li.filter(EFilterExcludeDNS) || li.filter(EFilterExcludeCANCEL) || li.subFilter(ESubFilterExcludeDNS) || li.subFilter(ESubFilterVacant)) { usedIx[k] = -2; // Skip totally } continue; } else usedIx[k] = -2; // Skip unless allowed after filters bool noResult = false; bool noPrelResult = false; bool noStart = false; bool cancelled = false; if (gResult == 0) { noResult = it->Runners[k]->tStatus == StatusUnknown; noPrelResult = it->Runners[k]->tStatus == StatusUnknown && it->Runners[k]->getRunningTime(false) <= 0; noStart = it->Runners[k]->tStatus == StatusDNS || it->Runners[k]->tStatus == StatusCANCEL; if (it->Runners[k]->Class && it->Runners[k]->Class->isQualificationFinalBaseClass()) { if (k > 0 && it->Runners[k]->getClassRef(true) == it->Runners[k]->Class) noStart = true; } cancelled = it->Runners[k]->tStatus == StatusCANCEL; //XXX TODO Multiday } else { noResult = it->Runners[k]->tmpResult.status == StatusUnknown; noPrelResult = it->Runners[k]->tmpResult.status == StatusUnknown && it->Runners[k]->tmpResult.runningTime <= 0; noStart = it->Runners[k]->tmpResult.status == StatusDNS || it->Runners[k]->tmpResult.status == StatusCANCEL; cancelled = it->Runners[k]->tmpResult.status == StatusCANCEL; } if (noResult && (li.filter(EFilterHasResult) || li.subFilter(ESubFilterHasResult))) continue; if (noPrelResult && (li.filter(EFilterHasPrelResult) || li.subFilter(ESubFilterHasPrelResult))) continue; if (noStart && (li.filter(EFilterExcludeDNS) || li.subFilter(ESubFilterExcludeDNS))) continue; if (cancelled && li.filter(EFilterExcludeCANCEL)) continue; if (it->Runners[k]->isVacant() && li.subFilter(ESubFilterVacant)) continue; if ((it->Runners[k]->tLeg < parLegRangeMin || it->Runners[k]->tLeg > parLegRangeMax) && needParRange) continue; usedIx[k] = tr.size(); tr.push_back(it->Runners[k]); } if (gResult) { gResult->sortTeamMembers(tr); for (size_t k = 0; k < tr.size(); k++) { bool suitableBreak = k < 2 || (k + 2) >= tr.size(); printPostInfo.keepToghether = suitableBreak; printPostInfo.par.relayLegIndex = tr[k] ? tr[k]->tLeg : -1; formatPrintPost(li.subListPost, printPostInfo, &*it, tr[k], it->Club, tr[k]->getClassRef(true), nullptr, nullptr, nullptr, -1); printPostInfo.counter.level3++; } } else { for (size_t k = 0; k < usedIx.size(); k++) { if (usedIx[k] == -2) continue; // Skip bool suitableBreak = k < 2 || (k + 2) >= usedIx.size(); printPostInfo.keepToghether = suitableBreak; printPostInfo.par.relayLegIndex = k; if (usedIx[k] == -1) { pCourse crs = it->Class ? it->Class->getCourse(k, it->StartNo) : 0; formatPrintPost(li.subListPost, printPostInfo, &*it, 0, it->Club, it->Class, crs, nullptr, nullptr, k); } else { formatPrintPost(li.subListPost, printPostInfo, &*it, tr[usedIx[k]], it->Club, tr[usedIx[k]]->getClassRef(true), nullptr, nullptr, nullptr, -1); } printPostInfo.counter.level3++; } } } else if (li.listSubType == li.EBaseTypeCoursePunches || li.listSubType == li.EBaseTypeAllPunches) { pRunner r = it->getRunner(linearLegSpec); if (!r) return true; listGeneratePunches(li, gdi, &*it, r, it->Club, it->Class); } } return true; }; if (li.listType == li.EBaseTypeRunner) { for (size_t k = 0; k < rlist.size(); k++) { pRunner it = rlist[k]; if (li.filterRunnerResult(gResult, *it)) continue; wstring newKey; printPostInfo.par.relayLegIndex = -1; calculatePrintPostKey(li.subHead, gdi, li.lp, it->tInTeam, &*it, it->Club, it->getClassRef(true), printPostInfo.counter, newKey); if (newKey != oldKey) { if (!oldKey.empty()) gdi.addStringUT(gdi.getCY() - 1, 0, pageNewPage, ""); gdi.addStringUT(pagePageInfo, it->getClass(true)); oldKey.swap(newKey); printPostInfo.counter.level2 = 0; printPostInfo.counter.level3 = 0; printPostInfo.reset(); printPostInfo.par.relayLegIndex = -1; formatPrintPost(li.subHead, printPostInfo, it->tInTeam, &*it, it->Club, it->getClassRef(true), nullptr, nullptr, nullptr, -1); } if (li.lp.filterInclude(printPostInfo.counter.level2 + 1, rlist[k])) { printPostInfo.reset(); printPostInfo.par.relayLegIndex = it->tLeg; formatPrintPost(li.listPost, printPostInfo, it->tInTeam, &*it, it->Club, it->getClassRef(true), nullptr, nullptr, nullptr, -1); if (li.listSubType == li.EBaseTypeCoursePunches || li.listSubType == li.EBaseTypeAllPunches) { listGeneratePunches(li, gdi, it->tInTeam, &*it, it->Club, it->getClassRef(true)); } } ++printPostInfo.counter; } } else if (li.listType == li.EBaseTypeTeam) { if (li.sortOrder != SortOrder::Custom) { pair legInfo = li.lp.getLegInfo(sampleClass); sortTeams(li.sortOrder, legInfo.first, legInfo.second, tlist); } if (!li.resultModule.empty()) { wstring src; gResult = getGeneralResult(li.resultModule, src).get(); oListInfo::ResultType resType = li.getResultType(); gResult->calculateTeamResults(tlist, false, resType, li.sortOrder == Custom, li.getParam().getInputNumber()); } // Range of runners to include int parLegRangeMin = 0, parLegRangeMax = 1000; pClass parLegRangeClass = nullptr; for (pTeam t : tlist) { formatTeam(t, true, parLegRangeMin, parLegRangeMax, parLegRangeClass); } } else if (li.listType == li.EBaseTypeClubRunner) { Clubs.sort(); map> clubToRunner; for (pRunner r : rlist) { int club = r->getClubId(); if (club == 0) continue; clubToRunner[club].push_back(r); } bool first = true; for (auto it = Clubs.begin(); it != Clubs.end(); ++it) { if (it->isRemoved()) continue; if (li.filter(EFilterVacant)) { if (it->getId() == getVacantClub(false)) continue; } if (li.filter(EFilterOnlyVacant)) { if (it->getId() != getVacantClub(false)) continue; } bool startClub = false; for (auto rit : clubToRunner[it->getId()]) { if (li.filterRunnerResult(gResult, *rit)) continue; if (!startClub) { if (!first) gdi.addStringUT(gdi.getCY() - 1, 0, pageNewPage, ""); else first = false; gdi.addStringUT(pagePageInfo, it->getName()); printPostInfo.counter.level2 = 0; printPostInfo.counter.level3 = 0; printPostInfo.reset(); printPostInfo.par.relayLegIndex = -1; formatPrintPost(li.subHead, printPostInfo, nullptr, nullptr, &*it, nullptr, nullptr, nullptr, nullptr, -1); startClub = true; } ++printPostInfo.counter; if (li.lp.filterInclude(printPostInfo.counter.level2, rit)) { printPostInfo.counter.level3 = 0; printPostInfo.reset(); printPostInfo.par.relayLegIndex = rit->tLeg; formatPrintPost(li.listPost, printPostInfo, nullptr, rit, &*it, rit->getClassRef(true), nullptr, nullptr, nullptr, -1); if (li.listSubType == li.EBaseTypeCoursePunches || li.listSubType == li.EBaseTypeAllPunches) { listGeneratePunches(li, gdi, rit->tInTeam, &*rit, rit->Club, rit->getClassRef(true)); } } }//Runners }//Clubs } else if (li.listType == li.EBaseTypeClubTeam) { Clubs.sort(); map> clubToTeam; for (pTeam t : tlist) { int club = t->getClubId(); if (club == 0) continue; clubToTeam[club].push_back(t); } bool first = true; int parLegRangeMin = 0, parLegRangeMax = 1000; pClass parLegRangeClass = nullptr; for (auto it = Clubs.begin(); it != Clubs.end(); ++it) { if (it->isRemoved()) continue; if (li.filter(EFilterVacant)) { if (it->getId() == getVacantClub(false)) continue; } if (li.filter(EFilterOnlyVacant)) { if (it->getId() != getVacantClub(false)) continue; } bool startClub = false; for (auto rit : clubToTeam[it->getId()]) { if (!startClub) { if (!first) gdi.addStringUT(gdi.getCY() - 1, 0, pageNewPage, ""); else first = false; gdi.addStringUT(pagePageInfo, it->getName()); printPostInfo.counter.level2 = 0; printPostInfo.counter.level3 = 0; printPostInfo.reset(); printPostInfo.par.relayLegIndex = -1; formatPrintPost(li.subHead, printPostInfo, nullptr, nullptr, &*it, nullptr, nullptr, nullptr, nullptr, -1); startClub = true; } formatTeam(rit, false, parLegRangeMin, parLegRangeMax, parLegRangeClass); }//Teams }//Clubs } else if (li.listType == oListInfo::EBaseTypeCourse) { Courses.sort(); oCourseList::iterator it; for (it = Courses.begin(); it != Courses.end(); ++it) { if (it->isRemoved()) continue; if (!li.lp.selection.empty()) { vector usageClass; it->getClasses(usageClass); bool used = false; while (!used && !usageClass.empty()) { used = li.lp.selection.count(usageClass.back()->getId()) > 0; usageClass.pop_back(); } if (!used) continue; } wstring newKey; calculatePrintPostKey(li.subHead, gdi, li.lp, 0, 0, 0, 0, printPostInfo.counter, newKey); if (newKey != oldKey) { if (!oldKey.empty()) gdi.addStringUT(gdi.getCY() - 1, 0, pageNewPage, ""); oldKey.swap(newKey); printPostInfo.counter.level2 = 0; printPostInfo.counter.level3 = 0; printPostInfo.reset(); formatPrintPost(li.subHead, printPostInfo, nullptr, nullptr, nullptr, nullptr, &*it, nullptr, nullptr, 0); } if (li.lp.filterInclude(printPostInfo.counter.level2 + 1, nullptr)) { printPostInfo.reset(); formatPrintPost(li.listPost, printPostInfo, nullptr, nullptr, nullptr, nullptr, &*it, nullptr, nullptr, 0); if (li.listSubType == li.EBaseTypeControl) { //TODO: listGeneratePunches(li.subListPost, gdi, li.lp, it->tInTeam, &*it, it->Club, it->Class); } } ++printPostInfo.counter; } } else if (li.listType == oListInfo::EBaseTypeControl) { Controls.sort(); oControlList::iterator it; for (it = Controls.begin(); it != Controls.end(); ++it) { if (it->isRemoved()) continue; wstring newKey; calculatePrintPostKey(li.subHead, gdi, li.lp, 0, 0, 0, 0, printPostInfo.counter, newKey); if (newKey != oldKey) { if (!oldKey.empty()) gdi.addStringUT(gdi.getCY() - 1, 0, pageNewPage, ""); oldKey.swap(newKey); printPostInfo.counter.level2 = 0; printPostInfo.counter.level3 = 0; printPostInfo.reset(); formatPrintPost(li.subHead, printPostInfo, nullptr, nullptr, nullptr, nullptr, nullptr, &*it, nullptr, 0); } if (li.lp.filterInclude(printPostInfo.counter.level2 + 1, nullptr)) { printPostInfo.reset(); formatPrintPost(li.listPost, printPostInfo, nullptr, nullptr, nullptr, nullptr, nullptr, &*it, nullptr, 0); } ++printPostInfo.counter; } } } void oEvent::fillListTypes(gdioutput &gdi, const string &name, int filter) { map listMap; getListTypes(listMap, filter); //gdi.clearList(name); map::iterator it; vector< pair > v; for (it=listMap.begin(); it!=listMap.end(); ++it) { v.push_back(make_pair(it->second.Name, it->first)); //gdi.addItem(name, it->second.Name, it->first); } sort(v.begin(), v.end()); gdi.setItems(name, v); } void oEvent::getListType(EStdListType type, oListInfo &li) { map listMap; getListTypes(listMap, false); li = listMap[type]; } void oEvent::getListTypes(map &listMap, int filterResults) { listMap.clear(); if (!filterResults) { oListInfo li; li.Name=lang.tl(L"Startlista, individuell"); li.listType=li.EBaseTypeRunner; li.supportClasses = true; li.supportLegs = true; listMap[EStdStartList]=li; } { oListInfo li; li.Name=lang.tl(L"Resultat, individuell"); li.listType=li.EBaseTypeRunner; li.supportClasses = true; li.supportLegs = true; li.supportFrom = true; li.supportTo = true; listMap[EStdResultList]=li; } { oListInfo li; li.Name=lang.tl(L"Resultat, generell"); li.listType=li.EBaseTypeRunner; li.supportClasses = true; li.supportLegs = true; li.supportLarge = true; li.supportFrom = true; li.supportTo = true; li.calcTotalResults = true; listMap[EGeneralResultList]=li; } { oListInfo li; li.Name=lang.tl(L"Rogaining, individuell"); li.listType=li.EBaseTypeRunner; li.supportClasses = true; li.supportLegs = true; listMap[ERogainingInd]=li; } { oListInfo li; li.Name=lang.tl(L"Avgjorda klasser (prisutdelningslista)"); li.listType=li.EBaseTypeRunner; li.supportClasses = true; li.supportLegs = true; listMap[EIndPriceList]=li; } if (!filterResults) { oListInfo li; li.Name=lang.tl(L"Startlista, patrull"); li.listType=li.EBaseTypeTeam; li.supportClasses = true; li.supportLegs = false; listMap[EStdPatrolStartList]=li; } { oListInfo li; li.Name=lang.tl(L"Resultat, patrull"); li.listType=li.EBaseTypeTeam; li.supportClasses = true; li.supportLegs = false; listMap[EStdPatrolResultList]=li; } { oListInfo li; li.Name=lang.tl(L"Patrullresultat (STOR)"); li.listType=li.EBaseTypeTeam; li.supportClasses = true; li.supportLegs = false; li.largeSize = true; listMap[EStdPatrolResultListLARGE]=li; } { oListInfo li; li.Name=lang.tl(L"Resultat (STOR)"); li.supportClasses = true; li.supportLegs = true; li.supportFrom = true; li.supportTo = true; li.largeSize = true; li.listType=li.EBaseTypeRunner; listMap[EStdResultListLARGE]=li; } /*{ oListInfo li; li.Name=lang.tl("Stafettresultat, sträcka (STOR)"); li.supportClasses = true; li.supportLegs = true; li.largeSize = true; li.listType=li.EBaseTypeTeam; listMap[EStdTeamResultListLegLARGE]=li; }*/ if (!filterResults) { oListInfo li; li.Name=lang.tl(L"Hyrbricksrapport"); li.listType=li.EBaseTypeRunner; li.supportClasses = false; li.supportLegs = false; listMap[EStdRentedCard]=li; } { oListInfo li; li.Name=lang.tl(L"Stafettresultat, delsträckor"); li.listType=li.EBaseTypeTeam; li.supportClasses = true; li.supportLegs = false; listMap[EStdTeamResultListAll]=li; } { oListInfo li; li.Name=lang.tl(L"Stafettresultat, lag"); li.listType=li.EBaseTypeTeam; li.supportClasses = true; li.supportLegs = false; listMap[EStdTeamResultList]=li; } /* { oListInfo li; li.Name=lang.tl("Stafettresultat, sträcka"); li.listType=li.EBaseTypeTeam; li.supportClasses = true; li.supportLegs = true; listMap[EStdTeamResultListLeg]=li; }*/ if (!filterResults) { { oListInfo li; li.Name=lang.tl(L"Startlista, stafett (lag)"); li.listType=li.EBaseTypeTeam; li.supportClasses = true; li.supportLegs = false; listMap[EStdTeamStartList]=li; } { oListInfo li; li.Name=lang.tl(L"Startlista, stafett (sträcka)"); li.listType=li.EBaseTypeTeam; li.supportClasses = true; li.supportLegs = true; listMap[EStdTeamStartListLeg]=li; } { oListInfo li; li.Name=lang.tl(L"Bantilldelning, stafett"); li.listType=li.EBaseTypeTeam; li.supportClasses = true; li.supportLegs = false; listMap[ETeamCourseList]=li; } { oListInfo li; li.Name=lang.tl(L"Bantilldelning, individuell"); li.listType=li.EBaseTypeRunner; li.supportClasses = true; li.supportLegs = false; listMap[EIndCourseList]=li; } { oListInfo li; li.Name=lang.tl(L"Individuell startlista, visst lopp"); li.listType=li.EBaseTypeTeam; li.supportClasses = true; li.supportLegs = true; listMap[EStdIndMultiStartListLeg]=li; } } { oListInfo li; li.Name=lang.tl(L"Individuell resultatlista, visst lopp"); li.listType=li.EBaseTypeTeam; li.supportClasses = true; li.supportLegs = true; listMap[EStdIndMultiResultListLeg]=li; } { oListInfo li; li.Name=lang.tl(L"Individuell resultatlista, visst lopp (STOR)"); li.listType=li.EBaseTypeTeam; li.supportClasses = true; li.supportLegs = true; li.largeSize = true; listMap[EStdIndMultiResultListLegLARGE]=li; } { oListInfo li; li.Name = lang.tl(L"Individuell resultatlista, alla lopp"); li.listType = li.EBaseTypeTeam; li.supportClasses = true; li.supportLegs = false; listMap[EStdIndMultiResultListAll]=li; } if (!filterResults) { oListInfo li; li.Name = lang.tl(L"Klubbstartlista"); li.listType = li.EBaseTypeClubRunner; li.supportClasses = true; li.supportLegs = false; listMap[EStdClubStartList]=li; } { oListInfo li; li.Name = lang.tl(L"Klubbresultatlista"); li.listType = li.EBaseTypeClubRunner; li.supportClasses = true; li.supportLegs = false; listMap[EStdClubResultList]=li; } if (!filterResults) { { oListInfo li; li.Name=lang.tl(L"Tävlingsrapport"); li.supportClasses = false; li.supportLegs = false; li.listType=li.EBaseTypeNone; listMap[EFixedReport]=li; } { oListInfo li; li.Name=lang.tl(L"Kontroll inför tävlingen"); li.supportClasses = false; li.supportLegs = false; li.listType=li.EBaseTypeNone; listMap[EFixedPreReport]=li; } { oListInfo li; li.Name=lang.tl(L"Kvar-i-skogen"); li.supportClasses = false; li.supportLegs = false; li.listType=li.EBaseTypeNone; listMap[EFixedInForest]=li; } { oListInfo li; li.Name=lang.tl(L"Fakturor"); li.supportClasses = false; li.supportLegs = false; li.listType=li.EBaseTypeNone; listMap[EFixedInvoices]=li; } { oListInfo li; li.Name=lang.tl(L"Ekonomisk sammanställning"); li.supportClasses = false; li.supportLegs = false; li.listType=li.EBaseTypeNone; listMap[EFixedEconomy]=li; } } /* { oListInfo li; li.Name=lang.tl("Först-i-mål, klassvis"); li.supportClasses = false; li.supportLegs = false; li.listType=li.EBaseTypeNone; listMap[EFixedResultFinishPerClass]=li; } { oListInfo li; li.Name=lang.tl("Först-i-mål, gemensam"); li.supportClasses = false; li.supportLegs = false; li.listType=li.EBaseTypeNone; listMap[EFixedResultFinish]=li; }*/ if (!filterResults) { oListInfo li; li.Name=lang.tl(L"Minutstartlista"); li.supportClasses = false; li.supportLegs = false; li.listType=li.EBaseTypeNone; listMap[EFixedMinuteStartlist]=li; } { oListInfo li; li.Name=lang.tl(L"Händelser - tidslinje"); li.supportClasses = true; li.supportLegs = false; li.listType=li.EBaseTypeNone; listMap[EFixedTimeLine]=li; } { oListInfo li; li.Name=lang.tl(L"Liveresultat, deltagare"); li.listType=li.EBaseTypeRunner; li.supportClasses = true; li.supportLegs = false; li.supportFrom = true; li.supportTo = true; li.supportSplitAnalysis = false; li.supportInterResults = false; li.supportPageBreak = false; li.supportClassLimit = false; li.supportCustomTitle = false; listMap[EFixedLiveResult]=li; } { oListInfo li; li.Name=lang.tl(L"Stafettresultat, sträcka (STOR)"); li.supportClasses = true; li.supportLegs = false; li.largeSize = true; li.listType=li.EBaseTypeTeam; listMap[EStdTeamAllLegLARGE]=li; } getListContainer().setupListInfo(EFirstLoadedList, listMap, filterResults != 0); } void oEvent::generateListInfo(const gdioutput& target, EStdListType lt, int classId, oListInfo &li) { oListParam par; if (classId!=0) par.selection.insert(classId); par.listCode=lt; generateListInfo(target, par, li); } int openRunnerTeamCB(gdioutput *gdi, GuiEventType type, BaseInfo *data); void oEvent::generateFixedList(gdioutput &gdi, const oListInfo &li) { wstring dmy; switch (li.lp.listCode) { case EFixedPreReport: generatePreReport(gdi); break; case EFixedReport: generateCompetitionReport(gdi); break; case EFixedInForest: generateInForestList(gdi, openRunnerTeamCB, 0); break; case EFixedEconomy: printInvoices(gdi, IPTAllPrint, dmy, true); break; case EFixedInvoices: printInvoices(gdi, IPTAllPrint, dmy, false); break; case EFixedMinuteStartlist: generateMinuteStartlist(gdi); break; case EFixedLiveResult: break; case EFixedTimeLine: gdi.clearPage(false); gdi.addString("", boldLarge, makeDash(L"Tidslinje - X#") + getName()); gdi.dropLine(); set<__int64> stored; vector events; map cName; for (oClassList::const_iterator it = Classes.begin(); it != Classes.end(); ++it) { if (!it->isRemoved()) cName[it->getId()] = it->getName(); } oe->getTimeLineEvents(li.lp.selection, events, stored, timeConstHour*24*7); gdi.fillDown(); int yp = gdi.getCY(); int xp = gdi.getCX(); int w1 = gdi.scaleLength(60); int w = gdi.scaleLength(110); int w2 = w1+w; for (size_t k = 0; k(ev.getSource(*this)); if (!r) continue; if (ev.getType() == oTimeLine::TLTFinish && r->getStatus() != StatusOK) continue; wstring name = L""; if (r) name = r->getCompleteIdentification() + L" "; gdi.addStringUT(yp, xp, 0, oe->getAbsTime(ev.getTime())); gdi.addStringUT(yp, xp + w1, 0, cName[ev.getClassId()], w-10); gdi.addStringUT(yp, xp + w2, 0, name + lang.tl(ev.getMessage())); yp += gdi.getLineHeight(); /*string detail = ev.getDetail(); if (detail.size() > 0) { gdi.addStringUT(yp, xp + w, 0, detail); yp += gdi.getLineHeight(); }*/ } gdi.refresh(); break; } } void oListInfo::setCallback(GUICALLBACK cb) { lp.cb=cb; for (list::iterator it = next.begin(); it != next.end(); ++it) { it->setCallback(cb); } } void oEvent::generateListInfo(const gdioutput& target, oListParam &par, oListInfo &li) { vector parV(1, par); generateListInfo(target, parV, li); } void oEvent::generateListInfo(const gdioutput& target, vector &par, oListInfo &li) { li.getParam().sourceParam = -1;// Reset source loadGeneralResults(false, false); for (size_t k = 0; k < par.size(); k++) { par[k].cb = 0; } map listMap; getListTypes(listMap, false); if (par.size() == 1) { generateListInfoAux(target, par[0], li, listMap[par[0].listCode].Name); set used; // Add linked lists oListParam *cPar = &par[0]; while (cPar->nextList>0) { if (used.count(cPar->nextList)) break; // Circular definition used.insert(cPar->nextList); used.insert(cPar->previousList); oListParam &nextPar = oe->getListContainer().getParam(cPar->nextList-1); li.next.push_back(oListInfo()); nextPar.cb = 0; generateListInfoAux(target, nextPar, li.next.back(), L""); cPar = &nextPar; } } else { for (size_t k = 0; k < par.size(); k++) { if (k > 0) { li.next.push_back(oListInfo()); } generateListInfoAux(target, par[k], k == 0 ? li : li.next.back(), li.Name = listMap[par[0].listCode].Name); } } } extern Image image; void oEvent::generateListInfoAux(const gdioutput& target, oListParam &par, oListInfo &li, const wstring &name) { const int lh=14; const int vspace=lh/2; int bib; pair ln; const double scale = 1.8; wstring ttl; Position pos; pClass sampleClass = 0; if (!par.selection.empty()) sampleClass = getClass(*par.selection.begin()); if (!sampleClass && !Classes.empty()) sampleClass = &*Classes.begin(); EStdListType lt=par.listCode; li=oListInfo(); li.lp = par; li.Name = name; li.lp.defaultName = li.Name; if (par.defaultName.empty()) par.defaultName = li.Name; if (par.name.empty()) par.name = li.Name; if (li.lp.name.empty()) li.lp.name = li.Name; switch (lt) { case EStdStartList: { li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Startlista - %s", true)), boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); int bib = 0; int rank = 0; if (hasBib(true, false)) { li.addListPost(oPrintPost(lRunnerBib, L"", normalText, 0, 0)); bib=40; } li.addListPost(oPrintPost(lRunnerStart, L"", normalText, 0+bib, 0)); li.addListPost(oPrintPost(lPatrolNameNames, L"", normalText, 70+bib, 0)); li.addListPost(oPrintPost(lPatrolClubNameNames, L"", normalText, 300+bib, 0)); if (hasRank()) { li.addListPost(oPrintPost(lRunnerRank, L"", normalText, 470+bib, 0)); rank = 50; } li.addListPost(oPrintPost(lRunnerCard, L"", normalText, 470+bib+rank, 0)); li.addSubHead(oPrintPost(lClassName, L"", boldText, 0, 12)); li.addSubHead(oPrintPost(lClassLength, lang.tl(L"%s meter"), boldText, 300+bib, 12)); li.addSubHead(oPrintPost(lClassStartName, L"", boldText, 470+bib+rank, 12)); li.addSubHead(oPrintPost(lString, L"", boldText, 470+bib, 16)); li.listType=li.EBaseTypeRunner; li.sortOrder=ClassStartTime; li.setFilter(EFilterExcludeDNS); break; } case EStdClubStartList: { li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Klubbstartlista - %s", true)), boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); if (hasBib(true, true)) { pos.add("bib", 40); li.addListPost(oPrintPost(lRunnerBib, L"", normalText, 0, 0)); } pos.add("start", li.getMaxCharWidth(this, par.selection, lRunnerStart, L"", normalText)); li.addListPost(oPrintPost(lRunnerStart, L"", normalText, pos.get("start"), 0)); if (hasRank()) { pos.add("rank", 50); li.addListPost(oPrintPost(lRunnerRank, L"", normalText, pos.get("rank"), 0)); } pos.add("name", li.getMaxCharWidth(this, par.selection, lRunnerName, L"", normalText)); li.addListPost(oPrintPost(lPatrolNameNames, L"", normalText, pos.get("name"), 0)); pos.add("class", li.getMaxCharWidth(this, par.selection, lClassName, L"", normalText)); li.addListPost(oPrintPost(lClassName, L"", normalText, pos.get("class"), 0)); pos.add("length", li.getMaxCharWidth(this, par.selection, lClassLength, L"%s m", normalText)); li.addListPost(oPrintPost(lClassLength, lang.tl(L"%s m"), normalText, pos.get("length"), 0)); pos.add("sname", li.getMaxCharWidth(this, par.selection, lClassStartName, L"", normalText)); li.addListPost(oPrintPost(lClassStartName, L"", normalText, pos.get("sname"), 0)); pos.add("card", 70); li.addListPost(oPrintPost(lRunnerCard, L"", normalText, pos.get("card"), 0)); li.addSubHead(oPrintPost(lClubName, L"", boldText, 0, 12)); li.addSubHead(oPrintPost(lString, L"", boldText, 100, 16)); li.listType=li.EBaseTypeClubRunner; li.sortOrder=ClassTeamLeg; li.setFilter(EFilterExcludeDNS); li.setFilter(EFilterVacant); break; } case EStdClubResultList: { li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Klubbresultatlista - %s", true)), boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); pos.add("class", li.getMaxCharWidth(this, par.selection, lClassName, L"", normalText)); li.addListPost(oPrintPost(lClassName, L"", normalText, pos.get("class"), 0)); pos.add("place", 40); li.addListPost(oPrintPost(lRunnerPlace, L"", normalText, pos.get("place"), 0)); pos.add("name", li.getMaxCharWidth(this, par.selection, lPatrolNameNames, L"", normalText)); li.addListPost(oPrintPost(lRunnerName, L"", normalText, pos.get("name"), 0)); pos.add("time", li.getMaxCharWidth(this, par.selection, lRunnerTimeStatus, L"", normalText)); li.addListPost(oPrintPost(lRunnerTimeStatus, L"", normalText, pos.get("time"), 0)); pos.add("after", li.getMaxCharWidth(this, par.selection, lRunnerTimeAfter, L"", normalText)); li.addListPost(oPrintPost(lRunnerTimeAfter, L"", normalText, pos.get("after"), 0)); li.addSubHead(oPrintPost(lClubName, L"", boldText, 0, 12)); li.addSubHead(oPrintPost(lString, L"", boldText, 100, 16)); li.listType=li.EBaseTypeClubRunner; li.sortOrder=ClassResult; li.calcResults = true; li.setFilter(EFilterVacant); break; } case EStdRentedCard: { li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Hyrbricksrapport - %s", true)), boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); li.addListPost(oPrintPost(lTotalCounter, L"%s", normalText, 0, 0)); li.addListPost(oPrintPost(lRunnerCard, L"", normalText, 30, 0)); li.addListPost(oPrintPost(lRunnerName, L"", normalText, 130, 0)); li.addSubHead(oPrintPost(lClassName, L"", boldText, 0, 10)); li.setFilter(EFilterHasCard); li.setFilter(EFilterRentCard); li.setFilter(EFilterExcludeDNS); li.listType=li.EBaseTypeRunner; li.sortOrder=ClassStartTime; break; } case EStdResultList: { wstring stitle; getResultTitle(*this, li.lp, stitle); stitle = par.getCustomTitle(stitle); li.addHead(oPrintPost(lCmpName, makeDash(stitle), boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); generateNBestHead(par, li, 25+lh); pos.add("place", 25); pos.add("name", li.getMaxCharWidth(this, par.selection, lPatrolNameNames, L"", normalText, 0, false, 25)); pos.add("club", li.getMaxCharWidth(this, par.selection, lPatrolClubNameNames, L"", normalText, 0, false, 25)); pos.add("status", li.getMaxCharWidth(this, par.selection, lRunnerTimeStatus, L"", normalText, 0, false, 25)); pos.add("after", li.getMaxCharWidth(this, par.selection, lRunnerTimeAfter, L"", normalText, 0, false, 25)); pos.add("missed", 50); li.addSubHead(oPrintPost(lClassName, L"", boldText, 0, 10)); li.addListPost(oPrintPost(lRunnerPlace, L"", normalText, pos.get("place"), 0)); li.addListPost(oPrintPost(lPatrolNameNames, L"", normalText, pos.get("name"), 0)); li.addListPost(oPrintPost(lPatrolClubNameNames, L"", normalText, pos.get("club"), 0)); if (li.lp.useControlIdResultTo<=0 && li.lp.useControlIdResultFrom<=0) { li.addSubHead(oPrintPost(lClassResultFraction, L"", boldText, pos.get("club"), 10)); li.addListPost(oPrintPost(lRunnerTimeStatus, L"", normalText, pos.get("status"), 0)); li.addListPost(oPrintPost(lRunnerTimeAfter, L"", normalText, pos.get("after"), 0)); if (li.lp.showInterTimes) { li.addSubListPost(oPrintPost(lPunchNamedTime, L"", italicSmall, pos.get("name"), 0, make_pair(1, true))); li.subListPost.back().fixedWidth = 160; li.listSubType = li.EBaseTypeCoursePunches; } else if (li.lp.showSplitTimes) { li.addSubListPost(oPrintPost(lPunchTime, L"", italicSmall, pos.get("name"), 0, make_pair(1, true))); li.subListPost.back().fixedWidth = 95; li.listSubType = li.EBaseTypeCoursePunches; } } else { li.needPunches = oListInfo::PunchMode::SpecificPunch; li.addListPost(oPrintPost(lRunnerTempTimeStatus, L"", normalText, pos.get("status"), 0)); li.addListPost(oPrintPost(lRunnerTempTimeAfter, L"", normalText, pos.get("after"), 0)); } li.addSubHead(oPrintPost(lString, lang.tl(L"Tid"), boldText, pos.get("status"), 10)); li.addSubHead(oPrintPost(lString, lang.tl(L"Efter"), boldText, pos.get("after"), 10)); if (li.lp.splitAnalysis) { li.addListPost(oPrintPost(lRunnerLostTime, L"", normalText, pos.get("missed"), 0)); li.addSubHead(oPrintPost(lString, lang.tl(L"Bomtid"), boldText, pos.get("missed"), 10)); } li.calcResults = true; li.listType=li.EBaseTypeRunner; li.sortOrder=ClassResult; li.supportFrom = true; li.supportTo = true; li.setFilter(EFilterHasPrelResult); li.setFilter(EFilterExcludeCANCEL); break; } case EGeneralResultList: { wstring stitle; getResultTitle(*this, li.lp, stitle); stitle = par.getCustomTitle(stitle); gdiFonts normal, header, small; double s; if (par.useLargeSize) { s = scale; normal = fontLarge; header = boldLarge; small = normalText; } else { s = 1.0; normal = normalText; header = boldText; small = italicSmall; } li.addHead(oPrintPost(lCmpName, makeDash(stitle), boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); generateNBestHead(par, li, 25+lh); pos.add("place", li.getMaxCharWidth(this, par.selection, lRunnerGeneralPlace, L"", normalText)); pos.add("name", li.getMaxCharWidth(this, par.selection, lRunnerCompleteName, L"", normalText)); pos.add("status", li.getMaxCharWidth(this, par.selection, lRunnerGeneralTimeStatus, L"", normalText)); pos.add("after", li.getMaxCharWidth(this, par.selection, lRunnerGeneralTimeAfter, L"", normalText)); pos.add("missed", 50); li.addSubHead(oPrintPost(lClassName, L"", header, 0, 10)); li.addListPost(oPrintPost(lRunnerGeneralPlace, L"", normal, pos.get("place", s), 0)); li.addListPost(oPrintPost(lRunnerCompleteName, L"", normal, pos.get("name", s), 0)); if (li.lp.useControlIdResultTo<=0 && li.lp.useControlIdResultFrom<=0) { li.addListPost(oPrintPost(lRunnerGeneralTimeStatus, L"", normal, pos.get("status", s), 0)); li.addListPost(oPrintPost(lRunnerGeneralTimeAfter, L"", normal, pos.get("after", s), 0)); if (li.lp.showInterTimes) { li.addSubListPost(oPrintPost(lPunchNamedTime, L"", small, pos.get("name", s), 0, make_pair(1, true))); li.subListPost.back().fixedWidth = 160; li.listSubType = li.EBaseTypeCoursePunches; } else if (li.lp.showSplitTimes) { li.addSubListPost(oPrintPost(lPunchTime, L"", small, pos.get("name", s), 0, make_pair(1, true))); li.subListPost.back().fixedWidth = 95; li.listSubType = li.EBaseTypeCoursePunches; } } else { li.needPunches = oListInfo::PunchMode::SpecificPunch; li.addListPost(oPrintPost(lRunnerTempTimeStatus, L"", normal, pos.get("status", s), 0)); li.addListPost(oPrintPost(lRunnerTempTimeAfter, L"", normal, pos.get("after", s), 0)); } li.addSubHead(oPrintPost(lString, lang.tl(L"Tid"), header, pos.get("status", s), 10)); li.addSubHead(oPrintPost(lString, lang.tl(L"Efter"), header, pos.get("after", s), 10)); li.calcResults = true; li.listType=li.EBaseTypeRunner; li.sortOrder=ClassResult; li.setFilter(EFilterHasPrelResult); li.setFilter(EFilterExcludeCANCEL); li.supportFrom = true; li.supportTo = true; li.calcTotalResults = true; break; } case EIndPriceList: li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Avgjorda placeringar - %s")), boldLarge, 0,0)); li.addHead(oPrintPost(lCurrentTime, lang.tl(L"Genererad: ") + L"%s", normalText, 0, 25)); generateNBestHead(par, li, 25+lh); pos.add("place", 25); pos.add("name", li.getMaxCharWidth(this, par.selection, lPatrolNameNames, L"", normalText)); pos.add("club", li.getMaxCharWidth(this, par.selection, lPatrolClubNameNames, L"", normalText)); pos.add("status", 80); pos.add("info", 80); li.addSubHead(oPrintPost(lClassName, L"", boldText, 0, 10)); li.addSubHead(oPrintPost(lClassResultFraction, L"", boldText, pos.get("club"), 10)); li.addSubHead(oPrintPost(lString, lang.tl(L"Tid"), boldText, pos.get("status"), 10)); li.addSubHead(oPrintPost(lString, lang.tl(L"Avgörs kl"), boldText, pos.get("info"), 10)); li.addListPost(oPrintPost(lRunnerPlace, L"", normalText, pos.get("place"), 0)); li.addListPost(oPrintPost(lPatrolNameNames, L"", normalText, pos.get("name"), 0)); li.addListPost(oPrintPost(lPatrolClubNameNames, L"", normalText, pos.get("club"), 0)); li.addListPost(oPrintPost(lRunnerTimeStatus, L"", normalText, pos.get("status"), 0)); li.addListPost(oPrintPost(lRunnerTimePlaceFixed, L"", normalText, pos.get("info"), 0)); li.calcResults = true; li.listType = li.EBaseTypeRunner; li.sortOrder = ClassResult; li.setFilter(EFilterHasResult); li.setFilter(EFilterExcludeCANCEL); break; case EStdTeamResultList: li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Resultatsammanställning - %s")), boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); generateNBestHead(par, li, 25+lh); li.addSubHead(oPrintPost(lClassName, L"", boldText, 0, 14)); li.addSubHead(oPrintPost(lClassResultFraction, L"", normalText, 280, 14)); //Use last leg for every team (index=-1) li.addListPost(oPrintPost(lTeamPlace, L"", normalText, 0, 5, make_pair(-1, true))); li.addListPost(oPrintPost(lTeamName, L"", normalText, 25, 5, make_pair(-1, true))); li.addListPost(oPrintPost(lTeamTimeStatus, L"", normalText, 280, 5, make_pair(-1, true))); li.addListPost(oPrintPost(lTeamTimeAfter, L"", normalText, 340, 5, make_pair(-1, true))); li.lp.setLegNumberCoded(-1); li.calcResults=true; li.listType=li.EBaseTypeTeam; li.listSubType=li.EBaseTypeRunner; li.sortOrder=ClassResult; li.setFilter(EFilterHasResult); li.setFilter(EFilterExcludeCANCEL); break; case EStdTeamResultListAll: li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Resultat - %s")), boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); generateNBestHead(par, li, 25+lh); li.addSubHead(oPrintPost(lClassName, L"", boldText, 0, 14)); li.addSubHead(oPrintPost(lClassResultFraction, L"", boldText, 280, 14)); li.addSubHead(oPrintPost(lString, lang.tl(L"Tid"), boldText, 400, 14)); li.addSubHead(oPrintPost(lString, lang.tl(L"Efter"), boldText, 460, 14)); //Use last leg for every team (index=-1) li.addListPost(oPrintPost(lTeamPlace, L"", normalText, 0, 5, make_pair(-1, true))); li.addListPost(oPrintPost(lTeamName, L"", normalText, 25, 5, make_pair(-1, true))); li.addListPost(oPrintPost(lTeamTimeStatus, L"", normalText, 400, 5, make_pair(-1, true))); li.addListPost(oPrintPost(lTeamTimeAfter, L"", normalText, 460, 5, make_pair(-1, true))); li.addSubListPost(oPrintPost(lRunnerLegNumberAlpha, L"%s.", normalText, 25, 0, make_pair(-1, true))); li.addSubListPost(oPrintPost(lRunnerName, L"", normalText, 45, 0, make_pair(-1, true))); li.addSubListPost(oPrintPost(lRunnerTimeStatus, L"", normalText, 280, 0, make_pair(-1, true))); li.addSubListPost(oPrintPost(lTeamLegTimeStatus, L"", normalText, 400, 0, make_pair(-1, true))); li.addSubListPost(oPrintPost(lTeamLegTimeAfter, L"", normalText, 460, 0, make_pair(-1, true))); if (li.lp.splitAnalysis) { li.addSubListPost(oPrintPost(lRunnerLostTime, L"", normalText, 510, 0)); li.addSubHead(oPrintPost(lString, lang.tl(L"Bomtid"), boldText, 510, 14)); } li.lp.setLegNumberCoded(-1); li.calcResults=true; li.listType=li.EBaseTypeTeam; li.listSubType=li.EBaseTypeRunner; li.sortOrder=ClassResult; li.setFilter(EFilterHasResult); li.setFilter(EFilterExcludeCANCEL); break; case unused_EStdTeamResultListLeg: { wchar_t title[256]; if (li.lp.getLegNumberCoded() != 1000) swprintf_s(title, (lang.tl(L"Resultat efter sträcka X#" + li.lp.getLegName())+L" - %%s").c_str()); else swprintf_s(title, (lang.tl(L"Resultat efter sträckan")+L" - %%s").c_str()); pos.add("place", 25); pos.add("team", li.getMaxCharWidth(this, par.selection, lTeamName, L"", normalText)); pos.add("name", li.getMaxCharWidth(this, par.selection, lRunnerName, L"", normalText)); pos.add("status", 50); pos.add("teamstatus", 50); pos.add("after", 50); pos.add("missed", 50); li.addHead(oPrintPost(lCmpName, makeDash(title), boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); generateNBestHead(par, li, 25+lh); li.addSubHead(oPrintPost(lClassName, L"", boldText, pos.get("place"), 14)); li.addSubHead(oPrintPost(lClassResultFraction, L"", boldText, pos.get("name"), 14)); li.addSubHead(oPrintPost(lString, lang.tl(L"Tid"), boldText, pos.get("status"), 14)); li.addSubHead(oPrintPost(lString, lang.tl(L"Totalt"), boldText, pos.get("teamstatus"), 14)); li.addSubHead(oPrintPost(lString, lang.tl(L"Efter"), boldText, pos.get("after"), 14)); ln = li.lp.getLegInfo(sampleClass); li.addListPost(oPrintPost(lTeamPlace, L"", normalText, pos.get("place"), 2, ln)); li.addListPost(oPrintPost(lTeamName, L"", normalText, pos.get("team"), 2, ln)); li.addListPost(oPrintPost(lRunnerName, L"", normalText, pos.get("name"), 2, ln)); li.addListPost(oPrintPost(lRunnerTimeStatus, L"", normalText, pos.get("status"), 2, ln)); li.addListPost(oPrintPost(lTeamTimeStatus, L"", normalText, pos.get("teamstatus"), 2, ln)); li.addListPost(oPrintPost(lTeamTimeAfter, L"", normalText, pos.get("after"), 2, ln)); if (li.lp.splitAnalysis) { li.addListPost(oPrintPost(lRunnerLostTime, L"", normalText, pos.get("missed"), 2, ln)); li.addSubHead(oPrintPost(lString, lang.tl(L"Bomtid"), boldText, pos.get("missed"), 14)); } li.calcResults=true; li.listType=li.EBaseTypeTeam; li.sortOrder=ClassResult; li.setFilter(EFilterHasResult); break; } case unused_EStdTeamResultListLegLARGE: { wchar_t title[256]; if (li.lp.getLegNumberCoded() != 1000) swprintf_s(title, (L"%%s - "+lang.tl(L"sträcka X#" + li.lp.getLegName())).c_str()); else swprintf_s(title, (L"%%s - "+lang.tl(L"slutsträckan")).c_str()); pos.add("place", 25); pos.add("team", min(120, li.getMaxCharWidth(this, par.selection, lTeamName, L"", normalText))); pos.add("name", min(120, li.getMaxCharWidth(this, par.selection, lRunnerName, L"", normalText))); pos.add("status", 50); pos.add("teamstatus", 50); pos.add("after", 50); pos.add("missed", 50); li.addSubHead(oPrintPost(lClassName, makeDash(title), boldLarge, pos.get("place", scale), 14)); li.addSubHead(oPrintPost(lClassResultFraction, L"", boldLarge, pos.get("name", scale), 14)); li.addSubHead(oPrintPost(lString, lang.tl(L"Tid"), boldLarge, pos.get("status", scale), 14)); li.addSubHead(oPrintPost(lString, lang.tl(L"Totalt"), boldLarge, pos.get("teamstatus", scale), 14)); li.addSubHead(oPrintPost(lString, lang.tl(L"Efter"), boldLarge, pos.get("after", scale), 14)); ln = li.lp.getLegInfo(sampleClass); li.addListPost(oPrintPost(lTeamPlace, L"", fontLarge, pos.get("place", scale), 5, ln)); li.addListPost(oPrintPost(lTeamName, L"", fontLarge, pos.get("team", scale), 5, ln)); li.addListPost(oPrintPost(lRunnerName, L"", fontLarge, pos.get("name", scale), 5, ln)); li.addListPost(oPrintPost(lRunnerTimeStatus, L"", fontLarge, pos.get("status", scale), 5, ln)); li.addListPost(oPrintPost(lTeamTimeStatus, L"", fontLarge, pos.get("teamstatus", scale), 5, ln)); li.addListPost(oPrintPost(lTeamTimeAfter, L"", fontLarge, pos.get("after", scale), 5, ln)); if (li.lp.splitAnalysis) { li.addListPost(oPrintPost(lRunnerLostTime, L"", fontLarge, pos.get("missed", scale), 5, ln)); li.addSubHead(oPrintPost(lString, lang.tl(L"Bomtid"), boldLarge, pos.get("missed", scale), 14)); } li.calcResults=true; li.listType=li.EBaseTypeTeam; li.sortOrder=ClassResult; li.setFilter(EFilterHasResult); break; } case EStdTeamStartList: { MetaList mList; mList.setListName(L"Startlista, stafett"); mList.addToHead(lCmpName).setText(L"Startlista - X");; mList.newHead(); mList.addToHead(lCmpDate); mList.addToSubHead(lClassName); mList.addToSubHead(MetaListPost(lClassStartTime, lNone)); mList.addToSubHead(MetaListPost(lClassLength, lNone)).setText(L"X meter"); mList.addToSubHead(MetaListPost(lClassStartName, lNone)); mList.addToList(lTeamBib); mList.addToList(lTeamStartCond); mList.addToList(lTeamName); mList.addToSubList(lRunnerLegNumberAlpha).align(lTeamName, false).setText(L"X."); mList.addToSubList(lRunnerName); mList.addToSubList(lRunnerCard).align(lClassStartName); mList.interpret(this, target, par, li); } li.listType=li.EBaseTypeTeam; li.listSubType=li.EBaseTypeRunner; //li.setFilter(EFilterExcludeDNS); li.setSubFilter(ESubFilterVacant); li.sortOrder = ClassStartTime; break; case ETeamCourseList: li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Bantilldelningslista - %s")), boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); li.listType=li.EBaseTypeTeam; bib=0; li.addListPost(oPrintPost(lTeamBib, L"", normalText, 0+bib, 4)); li.addListPost(oPrintPost(lTeamName, L"", normalText, 50+bib, 4)); li.addListPost(oPrintPost(lTeamClub, L"", normalText, 300+bib, 4)); li.listSubType=li.EBaseTypeRunner; li.addSubListPost(oPrintPost(lRunnerLegNumberAlpha, L"%s.", normalText, 25+bib, 0, make_pair(-1, true))); li.addSubListPost(oPrintPost(lRunnerName, L"", normalText, 50+bib, 0, make_pair(-1, true))); li.addSubListPost(oPrintPost(lRunnerCard, L"", normalText, 300+bib, 0, make_pair(-1, true))); li.addSubListPost(oPrintPost(lRunnerCourse, L"", normalText, 400+bib, 0, make_pair(-1, true))); li.addSubHead(oPrintPost(lClassName, L"", boldText, 0, 10)); li.addSubHead(oPrintPost(lString, lang.tl(L"Bricka"), boldText, 300+bib, 10)); li.addSubHead(oPrintPost(lString, lang.tl(L"Bana"), boldText, 400+bib, 10)); li.sortOrder = ClassStartTime; break; case EIndCourseList: { li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Bantilldelningslista - %s")), boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); li.listType=li.EBaseTypeRunner; bib=0; li.addListPost(oPrintPost(lRunnerBib, L"", normalText, 0+bib, 0)); oPrintPost &rn = li.addListPost(oPrintPost(lRunnerName, L"", normalText, 50+bib, 0)); rn.doMergeNext = true; li.addListPost(oPrintPost(lRunnerClub, L" (%s)", normalText, 50+bib, 0)); li.addListPost(oPrintPost(lRunnerCard, L"", normalText, 300+bib, 0)); li.addListPost(oPrintPost(lRunnerCourse, L"", normalText, 400+bib, 0)); li.addSubHead(oPrintPost(lClassName, L"", boldText, 0, 10)); li.addSubHead(oPrintPost(lString, lang.tl(L"Bricka"), boldText, 300+bib, 10)); li.addSubHead(oPrintPost(lString, lang.tl(L"Bana"), boldText, 400+bib, 10)); li.sortOrder = ClassStartTime; break; } case EStdTeamStartListLeg: { wchar_t title[256]; if (li.lp.getLegNumberCoded() == 1000) throw std::exception("Ogiltigt val av sträcka"); swprintf_s(title, lang.tl(L"Startlista %%s - sträcka X#" + li.lp.getLegName()).c_str()); li.addHead(oPrintPost(lCmpName, makeDash(title), boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); ln=li.lp.getLegInfo(sampleClass); li.listType=li.EBaseTypeTeam; bib=0; if (hasBib(false, true)) { li.addListPost(oPrintPost(lTeamBib, L"", normalText, 0, 0)); bib=40; } li.addListPost(oPrintPost(lTeamStart, L"", normalText, 0+bib, 0, ln)); li.addListPost(oPrintPost(lTeamName, L"", normalText, 70+bib, 0, ln)); li.addListPost(oPrintPost(lTeamRunner, L"", normalText, 300+bib, 0, ln)); li.addListPost(oPrintPost(lTeamRunnerCard, L"", normalText, 520+bib, 0, ln)); li.addSubHead(oPrintPost(lClassName, L"", boldText, 0, 10)); li.addSubHead(oPrintPost(lClassStartName, L"", normalText, 300+bib, 10)); li.sortOrder=ClassStartTime; //li.setFilter(EFilterExcludeDNS); break; } case EStdIndMultiStartListLeg: if (li.lp.getLegNumberCoded() == 1000) throw std::exception("Ogiltigt val av sträcka"); //sprintf_s(title, lang.tl("Startlista lopp %d - %%s").c_str(), li.lp.legNumber+1); ln=li.lp.getLegInfo(sampleClass); ttl = makeDash(lang.tl(L"Startlista lopp X - Y#" + li.lp.getLegName() + L"#%s")); li.addHead(oPrintPost(lCmpName, ttl, boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); li.listType=li.EBaseTypeTeam; bib=0; if (hasBib(false, true)) { li.addListPost(oPrintPost(lTeamBib, L"", normalText, 0, 0)); bib=40; } li.addListPost(oPrintPost(lTeamStart, L"", normalText, 0+bib, 0, ln)); li.addListPost(oPrintPost(lTeamRunner, L"", normalText, 70+bib, 0, ln)); li.addListPost(oPrintPost(lTeamClub, L"", normalText, 300+bib, 0, ln)); li.addListPost(oPrintPost(lTeamRunnerCard, L"", normalText, 500+bib, 0, ln)); li.addSubHead(oPrintPost(lClassName, L"", boldText, 0, 10)); li.addSubHead(oPrintPost(lClassLength, lang.tl(L"%s meter"), boldText, 300+bib, 10, ln)); li.addSubHead(oPrintPost(lClassStartName, L"", boldText, 500+bib, 10, ln)); li.sortOrder=ClassStartTime; li.setFilter(EFilterExcludeDNS); break; case EStdIndMultiResultListLeg: ln=li.lp.getLegInfo(sampleClass); if (li.lp.getLegNumberCoded() != 1000) ttl = lang.tl(L"Resultat lopp X - Y#" + li.lp.getLegName() + L"#%s"); else ttl = lang.tl(L"Resultat - X#%s"); li.addHead(oPrintPost(lCmpName, makeDash(ttl), boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); generateNBestHead(par, li, 25+lh); li.addSubHead(oPrintPost(lClassName, L"", boldText, 0, 14)); li.addSubHead(oPrintPost(lClassResultFraction, L"", boldText, 260, 14)); li.addSubHead(oPrintPost(lString, lang.tl(L"Tid"), boldText, 460, 14)); li.addSubHead(oPrintPost(lString, lang.tl(L"Totalt"), boldText, 510, 14)); li.addSubHead(oPrintPost(lString, lang.tl(L"Efter"), boldText, 560, 14)); li.addListPost(oPrintPost(lTeamPlace, L"", normalText, 0, 0, ln)); li.addListPost(oPrintPost(lRunnerName, L"", normalText, 40, 0, ln)); li.addListPost(oPrintPost(lRunnerClub, L"", normalText, 260, 0, ln)); li.addListPost(oPrintPost(lRunnerTimeStatus, L"", normalText, 460, 0, ln)); li.addListPost(oPrintPost(lTeamTimeStatus, L"", normalText, 510, 0, ln)); li.addListPost(oPrintPost(lTeamTimeAfter, L"", normalText, 560, 0, ln)); if (li.lp.splitAnalysis) { li.addListPost(oPrintPost(lRunnerLostTime, L"", normalText, 620, 0, ln)); li.addSubHead(oPrintPost(lString, lang.tl(L"Bomtid"), boldText, 620, 14)); } li.calcResults=true; li.listType=li.EBaseTypeTeam; li.sortOrder=ClassResult; li.setFilter(EFilterHasResult); li.setFilter(EFilterExcludeCANCEL); break; case EStdIndMultiResultListLegLARGE: if (li.lp.getLegNumberCoded() == 1000) throw std::exception("Ogiltigt val av sträcka"); ln=li.lp.getLegInfo(sampleClass); pos.add("place", 25); pos.add("name", li.getMaxCharWidth(this, par.selection, lRunnerName, L"", normalText)); pos.add("club", li.getMaxCharWidth(this, par.selection, lRunnerClub, L"", normalText)); pos.add("status", 50); pos.add("teamstatus", 50); pos.add("after", 50); ttl = L"%s - " + lang.tl(L"Lopp ") + li.lp.getLegName(); li.addSubHead(oPrintPost(lClassName, makeDash(ttl), boldLarge, pos.get("place", scale), 14)); li.addSubHead(oPrintPost(lClassResultFraction, L"", boldLarge, pos.get("club", scale), 14)); li.addSubHead(oPrintPost(lString, lang.tl(L"Tid"), boldLarge, pos.get("status", scale), 14)); li.addSubHead(oPrintPost(lString, lang.tl(L"Totalt"), boldLarge, pos.get("teamstatus", scale), 14)); li.addSubHead(oPrintPost(lString, lang.tl(L"Efter"), boldLarge, pos.get("after", scale), 14)); li.addListPost(oPrintPost(lTeamPlace, L"", fontLarge, pos.get("place", scale), 0, ln)); li.addListPost(oPrintPost(lRunnerName, L"", fontLarge, pos.get("name", scale), 0, ln)); li.addListPost(oPrintPost(lRunnerClub, L"", fontLarge, pos.get("club", scale), 0, ln)); li.addListPost(oPrintPost(lRunnerTimeStatus, L"", fontLarge, pos.get("status", scale), 0, ln)); li.addListPost(oPrintPost(lTeamTimeStatus, L"", fontLarge, pos.get("teamstatus", scale), 0, ln)); li.addListPost(oPrintPost(lTeamTimeAfter, L"", fontLarge, pos.get("after", scale), 0, ln)); li.calcResults=true; li.listType=li.EBaseTypeTeam; li.sortOrder=ClassResult; li.setFilter(EFilterHasResult); li.setFilter(EFilterExcludeCANCEL); break; case EStdIndMultiResultListAll: li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Resultat - %s")), boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); generateNBestHead(par, li, 25+lh); li.addSubHead(oPrintPost(lClassName, L"", boldText, 0, 14)); li.addSubHead(oPrintPost(lClassResultFraction, L"", boldText, 280, 14)); li.addSubHead(oPrintPost(lClassResultFraction, lang.tl(L"Tid"), boldText, 480, 14)); li.addSubHead(oPrintPost(lClassResultFraction, lang.tl(L"Efter"), boldText, 540, 14)); //Use last leg for every team (index=-1) li.addListPost(oPrintPost(lTeamPlace, L"", normalText, 0, 5, make_pair(-1, true))); li.addListPost(oPrintPost(lRunnerName, L"", normalText, 25, 5, make_pair(-1, true))); li.addListPost(oPrintPost(lRunnerClub, L"", normalText, 280, 5, make_pair(-1, true))); li.addListPost(oPrintPost(lTeamTimeStatus, L"", normalText, 480, 5, make_pair(-1, true))); li.addListPost(oPrintPost(lTeamTimeAfter, L"", normalText, 540, 5, make_pair(-1, true))); li.addSubListPost(oPrintPost(lSubSubCounter, lang.tl(L"Lopp %s"), normalText, 25, 0, make_pair(-1, true))); li.addSubListPost(oPrintPost(lRunnerTimeStatus, L"", normalText, 90, 0, make_pair(-1, true))); li.addSubListPost(oPrintPost(lTeamLegTimeStatus, L"", normalText, 150, 0, make_pair(-1, true))); li.addSubListPost(oPrintPost(lTeamLegTimeAfter, L"", normalText, 210, 0, make_pair(-1, true))); li.lp.setLegNumberCoded(-1); li.calcResults=true; li.listType=li.EBaseTypeTeam; li.listSubType=li.EBaseTypeRunner; li.sortOrder=ClassResult; li.setFilter(EFilterHasResult); li.setFilter(EFilterExcludeCANCEL); break; case EStdPatrolStartList: { MetaList mList; mList.setListName(L"Startlista, patrull"); mList.addToHead(lCmpName).setText(L"Startlista - X").align(false); mList.newHead(); mList.addToHead(lCmpDate).align(false); mList.addToSubHead(lClassName); mList.addToSubHead(lClassStartTime); mList.addToSubHead(lClassLength).setText(L"X meter"); mList.addToSubHead(lClassStartName); mList.addToList(lTeamBib); mList.addToList(lTeamStartCond).setLeg(0); mList.addToList(lTeamName); mList.newListRow(); mList.addToList(MetaListPost(lTeamRunner, lTeamName, 0)); mList.addToList(MetaListPost(lTeamRunnerCard, lAlignNext, 0)); mList.addToList(MetaListPost(lTeamRunner, lAlignNext, 1)); mList.addToList(MetaListPost(lTeamRunnerCard, lAlignNext, 1)); mList.setListType(li.EBaseTypeTeam); mList.setSortOrder(ClassStartTime); mList.addFilter(EFilterExcludeDNS); mList.interpret(this, target, par, li); break; } case EStdPatrolResultList: li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Resultatlista - %s")), boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); generateNBestHead(par, li, 25+lh); li.addListPost(oPrintPost(lTeamPlace, L"", normalText, 0, vspace, make_pair(1, true))); li.addListPost(oPrintPost(lTeamName, L"", normalText, 70, vspace)); //li.addListPost(oPrintPost(lTeamClub, "", normalText, 250, vspace)); li.addListPost(oPrintPost(lTeamTimeStatus, L"", normalText, 400, vspace, make_pair(1, true))); li.addListPost(oPrintPost(lTeamTimeAfter, L"", normalText, 460, vspace, make_pair(1, true))); li.addListPost(oPrintPost(lTeamRunner, L"", normalText, 70, lh+vspace, make_pair(0, true))); li.addListPost(oPrintPost(lTeamRunner, L"", normalText, 250, lh+vspace, make_pair(1, true))); li.setFilter(EFilterHasResult); li.addSubHead(oPrintPost(lClassName, L"", boldText, 0, 10)); li.addSubHead(oPrintPost(lString, lang.tl(L"Tid"), boldText, 400, 10)); li.addSubHead(oPrintPost(lString, lang.tl(L"Efter"), boldText, 460, 10)); if (li.lp.showInterTimes) { li.addSubListPost(oPrintPost(lPunchNamedTime, L"", normalText, 10, 0, make_pair(1, true))); li.subListPost.back().fixedWidth=160; li.listSubType=li.EBaseTypeCoursePunches; } if (li.lp.splitAnalysis) { li.addListPost(oPrintPost(lRunnerLostTime, L"", normalText, 520, vspace, make_pair(1, true))); li.addSubHead(oPrintPost(lString, lang.tl(L"Bomtid"), boldText, 520, 10)); } li.listType=li.EBaseTypeTeam; li.sortOrder=ClassResult; li.lp.setLegNumberCoded(-1); li.calcResults=true; li.setFilter(EFilterExcludeCANCEL); break; case EStdPatrolResultListLARGE: pos.add("place", 25); pos.add("team", int(0.7*max(li.getMaxCharWidth(this, par.selection, lTeamName, L"", normalText), li.getMaxCharWidth(this, par.selection, lPatrolNameNames, L"", normalText)))); pos.add("status", 50); pos.add("after", 50); pos.add("missed", 50); li.addListPost(oPrintPost(lTeamPlace, L"", fontLarge, pos.get("place", scale), vspace, make_pair(1, true))); li.addListPost(oPrintPost(lTeamName, L"", fontLarge, pos.get("team", scale), vspace)); li.addListPost(oPrintPost(lTeamTimeStatus, L"", fontLarge, pos.get("status", scale), vspace, make_pair(1, true))); li.addListPost(oPrintPost(lTeamTimeAfter, L"", fontLarge, pos.get("after", scale), vspace, make_pair(1, true))); li.addListPost(oPrintPost(lPatrolNameNames, L"", fontLarge, pos.get("team", scale), 25+vspace, make_pair(0, true))); //li.addListPost(oPrintPost(lTeamRunner, "", fontLarge, pos.get("status", scale), 25+vspace, 1)); li.addSubHead(oPrintPost(lClassName, L"", boldLarge, 0, 10)); li.addSubHead(oPrintPost(lString, lang.tl(L"Tid"), boldLarge, pos.get("status", scale), 10)); li.addSubHead(oPrintPost(lString, lang.tl(L"Efter"), boldLarge, pos.get("after", scale), 10)); if (li.lp.showInterTimes) { li.addSubListPost(oPrintPost(lPunchNamedTime, L"", normalText, 10, 0, make_pair(1, true))); li.subListPost.back().fixedWidth=200; li.listSubType=li.EBaseTypeCoursePunches; } if (li.lp.splitAnalysis) { li.addListPost(oPrintPost(lRunnerLostTime, L"", fontLarge, pos.get("missed", scale), vspace, make_pair(0, true))); li.addSubHead(oPrintPost(lString, lang.tl(L"Bomtid"), boldLarge, pos.get("missed", scale), 10)); } li.setFilter(EFilterHasResult); li.setFilter(EFilterExcludeCANCEL); li.listType=li.EBaseTypeTeam; li.sortOrder=ClassResult; li.lp.setLegNumberCoded(-1); li.calcResults=true; break; case unused_EStdRaidResultListLARGE: li.addListPost(oPrintPost(lTeamPlace, L"", fontLarge, 0, vspace)); li.addListPost(oPrintPost(lTeamName, L"", fontLarge, 40, vspace)); li.addListPost(oPrintPost(lTeamTimeStatus, L"", fontLarge, 490, vspace)); li.addListPost(oPrintPost(lTeamRunner, L"", fontLarge, 40, 25+vspace, make_pair(0, true))); li.addListPost(oPrintPost(lTeamRunner, L"", fontLarge, 300, 25+vspace, make_pair(1, true))); li.addSubListPost(oPrintPost(lPunchNamedTime, L"", fontMedium, 0, 2, make_pair(1, true))); li.subListPost.back().fixedWidth=200; li.setFilter(EFilterHasResult); li.addSubHead(oPrintPost(lClassName, L"", boldLarge, 0, 10)); li.listType=li.EBaseTypeTeam; li.listSubType=li.EBaseTypeCoursePunches; li.sortOrder=ClassResult; li.calcResults=true; break; case EStdResultListLARGE: pos.add("place", 25); pos.add("name", li.getMaxCharWidth(this, par.selection, lPatrolNameNames, L"", normalText, 0, true)); pos.add("club", li.getMaxCharWidth(this, par.selection, lPatrolClubNameNames, L"", normalText, 0, true)); pos.add("status", 50); pos.add("missed", 50); li.addListPost(oPrintPost(lRunnerPlace, L"", fontLarge, pos.get("place", scale), vspace)); li.addListPost(oPrintPost(lPatrolNameNames, L"", fontLarge, pos.get("name", scale), vspace)); li.addListPost(oPrintPost(lPatrolClubNameNames, L"", fontLarge, pos.get("club", scale), vspace)); li.addSubHead(oPrintPost(lClassName, L"", boldLarge, pos.get("place", scale), 10)); if (li.lp.useControlIdResultTo<=0 && li.lp.useControlIdResultFrom<=0) { li.addSubHead(oPrintPost(lClassResultFraction, L"", boldLarge, pos.get("club", scale), 10)); li.addListPost(oPrintPost(lRunnerTimeStatus, L"", fontLarge, pos.get("status", scale), vspace)); } else { li.needPunches = oListInfo::PunchMode::SpecificPunch; li.addListPost(oPrintPost(lRunnerTempTimeStatus, L"", normalText, pos.get("status", scale), vspace)); } if (li.lp.splitAnalysis) { li.addSubHead(oPrintPost(lString, lang.tl(L"Bomtid"), boldLarge, pos.get("missed", scale), 10)); li.addListPost(oPrintPost(lRunnerLostTime, L"", fontLarge, pos.get("missed", scale), vspace)); } if (li.lp.showInterTimes) { li.addSubListPost(oPrintPost(lPunchNamedTime, L"", normalText, 0, 0, make_pair(1, true))); li.subListPost.back().fixedWidth = 160; li.listSubType = li.EBaseTypeCoursePunches; } else if (li.lp.showSplitTimes) { li.addSubListPost(oPrintPost(lPunchTime, L"", normalText, 0, 0, make_pair(1, true))); li.subListPost.back().fixedWidth = 95; li.listSubType = li.EBaseTypeCoursePunches; } li.setFilter(EFilterHasResult); li.setFilter(EFilterExcludeCANCEL); li.lp.setLegNumberCoded(0); li.listType=li.EBaseTypeRunner; li.sortOrder=ClassResult; li.calcResults=true; li.supportFrom = true; li.supportTo = true; break; case EStdUM_Master: li.addListPost(oPrintPost(lRunnerPlace, L"", fontMedium, 0, 0)); li.addListPost(oPrintPost(lRunnerName, L"", fontMedium, 40, 0)); li.addListPost(oPrintPost(lRunnerClub, L"", fontMedium, 250, 0)); li.addListPost(oPrintPost(lClassName, L"", fontMedium, 490, 0)); li.addListPost(oPrintPost(lRunnerUMMasterPoint, L"", fontMedium, 580, 0)); li.setFilter(EFilterHasResult); li.lp.setLegNumberCoded(0); li.listType=li.EBaseTypeRunner; li.sortOrder=ClassResult; li.calcResults=true; break; case ERogainingInd: pos.add("place", 25); pos.add("name", li.getMaxCharWidth(this, par.selection, lRunnerCompleteName, L"", normalText, 0, true)); pos.add("points", 50); pos.add("status", 50); li.addHead(oPrintPost(lCmpName, makeDash(par.getCustomTitle(lang.tl(L"Rogainingresultat - %s"))), boldLarge, 0,0)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25)); generateNBestHead(par, li, 25+lh); li.addListPost(oPrintPost(lRunnerPlace, L"", normalText, pos.get("place"), vspace)); li.addListPost(oPrintPost(lRunnerCompleteName, L"", normalText, pos.get("name"), vspace)); li.addListPost(oPrintPost(lRunnerRogainingPoint, L"%sp", normalText, pos.get("points"), vspace)); li.addListPost(oPrintPost(lRunnerTimeStatus, L"", normalText, pos.get("status"), vspace)); li.setFilter(EFilterHasResult); li.setFilter(EFilterExcludeCANCEL); if (li.lp.splitAnalysis || li.lp.showInterTimes) { li.addSubListPost(oPrintPost(lRogainingPunch, L"", normalText, 10, 0, make_pair(1, true))); li.subListPost.back().fixedWidth=130; li.listSubType=li.EBaseTypeCoursePunches; } li.addSubHead(oPrintPost(lClassName, L"", boldText, pos.get("place"), 10)); li.addSubHead(oPrintPost(lString, lang.tl(L"Poäng"), boldText, pos.get("points"), 10)); li.addSubHead(oPrintPost(lString, lang.tl(L"Tid"), boldText, pos.get("status"), 10)); li.listType=li.EBaseTypeRunner; li.sortOrder = ClassPoints; li.lp.setLegNumberCoded(-1); li.calcResults = true; li.rogainingResults = true; break; case EStdTeamAllLegLARGE: { vector< pair > out; fillLegNumbers(par.selection, false, false, out); par.listCode = oe->getListContainer().getType("legresult"); par.useLargeSize = true; for (size_t k = 0; k < out.size(); k++) { if (out[k].second >= 1000) continue; par.setLegNumberCoded(out[k].second); if (k == 0) generateListInfo(target, par, li); else { li.next.push_back(oListInfo()); generateListInfo(target, par, li.next.back()); } } } break; case EFixedPreReport: case EFixedReport: case EFixedInForest: case EFixedEconomy: case EFixedInvoices: case EFixedMinuteStartlist: case EFixedTimeLine: case EFixedLiveResult: li.fixedType = true; break; default: if (!getListContainer().interpret(this, target, par, li)) throw meosException("Could not load list 'X'#L" + itos(par.listCode)); } } string oPrintPost::encodeFont(const string &face, int factor) { string out(face); if (factor > 0 && factor != 100) { out += ";" + itos(factor/100) + "." + itos(factor%100); } return out; } wstring oPrintPost::encodeFont(const wstring &face, int factor) { wstring out(face); if (factor > 0 && factor != 100) { out += L";" + itow(factor/100) + L"." + itow(factor%100); } return out; } void oListInfo::setupLinks(const list &lst) const { for (list::const_iterator it = lst.begin(); it != lst.end(); ++it) { list::const_iterator itNext = it; ++itNext; if (itNext != lst.end() && it->doMergeNext) it->mergeWithTmp = &*itNext; else it->mergeWithTmp = 0; } } void oListInfo::setupLinks() const { setupLinks(head); setupLinks(subHead); setupLinks(listPost); setupLinks(subListPost); } void oListInfo::shrinkSize() { auto scale = [](int& format) -> double { int highFormat = format & ~0xFF; format &= 0xFF; double s = 1.0; double fs = GDIImplFontSet::baseSize(format, 1.0); if (format == boldLarge) format = boldText; else if (format == boldHuge) format = boldLarge; else if (format == boldText) format = boldSmall; else if (format == normalText || format == fontMedium) format = fontSmall; else if (format = fontMediumPlus || format == fontLarge) format = fontMedium; else if (format == italicText) format = italicSmall; else if (format == italicMediumPlus) format = italicText; double fsNew = GDIImplFontSet::baseSize(format, 1.0); format |= highFormat; return fsNew/fs; }; auto scaleForward = [](oPrintPost& pp, double scale, list &pList, map &yOffset) { if (pp.xlimit > 0) pp.xlimit = int(pp.xlimit*scale); int minDX = -1; for (auto& h : pList) { if (h.dy == pp.dy && h.dx > pp.dx) { int df = h.dx - pp.dx; //h.dx = pp.dx + int(df * scale); int dx = h.dx - (pp.dx + int(df * scale)); assert(dx >= 0); if (minDX == -1 || dx < minDX) minDX = dx; } } for (auto& h : pList) { if (h.dy == pp.dy && h.dx > pp.dx) { h.dx -= minDX; } } int dy = 0; for (auto& h : pList) { if (h.dy > pp.dy) { dy = h.dy - int(pp.dy + (h.dy - pp.dy) * scale); auto res = yOffset.emplace(pp.dy, dy); if (!res.second) { if (dy > res.first->second) { // Already moved. Only do the extra offset and store the highest offset. int newDY = dy - res.first->second; res.first->second = dy; dy = newDY; } } break; } } if (dy > 0) { for (auto& h : pList) { if (h.dy > pp.dy) { h.dy -= dy; } } } }; list* allList[4] = { &head, &subHead, &listPost, &subListPost }; // Store original position in a map map>> xOffsetToListPost; for (int j = 0; j < 4; j++) { list& lp = *allList[j]; int ix = 0; for (auto& h : lp) { int off = h.dx; xOffsetToListPost[off].emplace_back(j, ix); ix++; } } for (int j = 0; j < 4; j++) { list& lp = *allList[j]; map yOffsets; for (auto& h : lp) { double s = scale(h.format); if (s < 1.0) scaleForward(h, s, lp, yOffsets); } } map, oPrintPost*> listPostToOffsetAfter; for (int j = 0; j < 4; j++) { list& lp = *allList[j]; int ix = 0; for (auto& h : lp) { listPostToOffsetAfter[make_pair(j, ix)] = &h; ix++; } } for (auto& it : xOffsetToListPost) { int minNewPos = -1; for (pair& lpIx : it.second) { oPrintPost &pp = *listPostToOffsetAfter[lpIx]; if (minNewPos == -1 || minNewPos > pp.dx) minNewPos = pp.dx; } for (pair& lpIx : it.second) { oPrintPost& pp = *listPostToOffsetAfter[lpIx]; int off = pp.dx - minNewPos; if (off > 0) { pp.dx = minNewPos; // TODO: Offset forward } } } /*for (auto& h : Head) { scale(h.format); } for (auto& h : subHead) { scale(h.format); } for (auto& h : listPost) { double s = scale(h.format); if (s < 1.0) scaleForward(h, s, listPost); } for (auto& h : subListPost) { scale(h.format); }*/ } oListInfo::ResultType oListInfo::getResultType() const { return resType; } bool oListParam::matchLegNumber(const pClass cls, int leg) const { if (cls == 0 || legNumber == -1 || leg < 0) return true; int number, order; cls->splitLegNumberParallel(leg, number, order); if (number == legNumber) return true; int sub = legNumber % 10000; int maj = legNumber / 10000; return maj == number + 1 && sub == order; } int oListParam::getLegNumber(const pClass cls) const { if (legNumber < 0) return legNumber; int sub = legNumber % 10000; int maj = legNumber / 10000; if (cls) { if (legNumber < 10000) return cls->getLegNumberLinear(legNumber, 0); else return cls->getLegNumberLinear(maj-1, sub); } return sub; } pair oListParam::getLegInfo(const pClass cls) const { if (legNumber == -1) return make_pair(-1, true); else if (legNumber < 10000) return make_pair(legNumber, false); int sub = legNumber % 10000; int maj = legNumber / 10000; int lin = cls ? cls->getLegNumberLinear(maj-1, sub) : sub+maj; return make_pair(lin, true); } wstring oListParam::getLegName() const { if (legNumber == -1) return L""; if (legNumber < 1000) return itow(legNumber + 1); int sub = legNumber % 10000; int maj = legNumber / 10000; wchar_t bf[64]; char symb = 'a' + sub; swprintf_s(bf, L"%d%c", maj, symb); return bf; } void SplitPrintListInfo::serialize(xmlparser& xml) const { xml.writeBool("Split", includeSplitTimes); xml.writeBool("Speed", withSpeed); xml.writeBool("Result", withResult); xml.writeBool("Analysis", withAnalysis); xml.writeBool("Heading", withStandardHeading); xml.write("NumClsResult", numClassResults); } void SplitPrintListInfo::deserialize(const xmlobject& xml) { includeSplitTimes = xml.getObjectBool("Split"); withSpeed = xml.getObjectBool("Speed"); withResult = xml.getObjectBool("Result"); withAnalysis = xml.getObjectBool("Analysis"); withStandardHeading = xml.getObjectBool("Heading"); if (xml.got("NumClsResult")) numClassResults = xml.getObjectInt("NumClsResult"); } int64_t SplitPrintListInfo::checkSum() const { int64_t ch = 0; ch = 2 * ch + includeSplitTimes; ch = 2 * ch + withSpeed; ch = 2 * ch + withResult; ch = 2 * ch + withAnalysis; return ch; }