Development version
This commit is contained in:
parent
16272ffa20
commit
a1a05bd56d
@ -1585,10 +1585,14 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
wstring bib;
|
||||
bool doBibs = false;
|
||||
|
||||
bool bibToVacant = true;
|
||||
if (gdi.hasWidget("Bib")) {
|
||||
bib = gdi.getText("Bib");
|
||||
doBibs = gdi.isChecked("HandleBibs");
|
||||
if (gdi.hasWidget("VacantBib")) {
|
||||
bibToVacant = gdi.isChecked("VacantBib");
|
||||
oe->getDI().setInt("NoVacantBib", bibToVacant ? 0 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
wstring time = gdi.getText("FirstStart");
|
||||
@ -1680,7 +1684,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
throw std::exception("Not implemented");
|
||||
|
||||
if (doBibs)
|
||||
oe->addBib(cid, leg, bib);
|
||||
oe->addBib(cid, leg, bib, bibToVacant);
|
||||
|
||||
// Clear input
|
||||
gdi.restore("", false);
|
||||
@ -1703,6 +1707,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
}
|
||||
else if (bi.id=="HandleBibs") {
|
||||
gdi.setInputStatus("Bib", gdi.isChecked("HandleBibs"));
|
||||
gdi.setInputStatus("VacantBib", gdi.isChecked("HandleBibs"), true);
|
||||
}
|
||||
else if (bi.id == "DoDeleteStart") {
|
||||
pClass pc=oe->getClass(ClassId);
|
||||
@ -1878,10 +1883,19 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
gdi.fillRight();
|
||||
gdi.popX();
|
||||
gdi.addString("", 0, "Antal reserverade nummerlappsnummer mellan klasser:");
|
||||
gdi.dropLine(-0.1);
|
||||
gdi.dropLine(-0.2);
|
||||
gdi.addInput("BibGap", itow(oe->getBibClassGap()), 5);
|
||||
gdi.dropLine(3);
|
||||
|
||||
gdi.dropLine(2.4);
|
||||
gdi.popX();
|
||||
|
||||
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Vacancy)) {
|
||||
bool bibToVacant = oe->getDCI().getInt("NoVacantBib") == 0;
|
||||
gdi.addCheckbox("VacantBib", "Tilldela nummerlapp till vakanter", nullptr, bibToVacant);
|
||||
gdi.dropLine(2.5);
|
||||
gdi.popX();
|
||||
}
|
||||
|
||||
gdi.fillRight();
|
||||
gdi.addButton("DoBibs", "Tilldela", ClassesCB).setDefault();
|
||||
|
||||
@ -1914,11 +1928,17 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
pc->setBibMode(BibMode(teamBib.first));
|
||||
}
|
||||
|
||||
bool bibToVacant = true;
|
||||
if (gdi.hasWidget("VacantBib")) {
|
||||
bibToVacant = gdi.isChecked("VacantBib");
|
||||
oe->getDI().setInt("NoVacantBib", bibToVacant ? 0 : 1);
|
||||
}
|
||||
|
||||
pc->getDI().setString("Bib", getBibCode(bt, gdi.getText("Bib")));
|
||||
pc->synchronize();
|
||||
int leg = pc->getParentClass() ? -1 : 0;
|
||||
if (bt == AutoBibManual) {
|
||||
oe->addBib(cid, leg, gdi.getText("Bib"));
|
||||
oe->addBib(cid, leg, gdi.getText("Bib"), bibToVacant);
|
||||
}
|
||||
else {
|
||||
oe->setBibClassGap(gdi.getTextNo("BibGap"));
|
||||
@ -3691,6 +3711,16 @@ void TabClass::saveClassSettingsTable(gdioutput &gdi) {
|
||||
}
|
||||
}
|
||||
|
||||
if (gdi.hasWidget("VacantBib")) {
|
||||
bool vacantBib = gdi.isChecked("VacantBib");
|
||||
bool vacantBibStored = oe->getDCI().getInt("NoVacantBib") == 0;
|
||||
|
||||
if (vacantBib != vacantBibStored) {
|
||||
oe->getDI().setInt("NoVacantBib", vacantBib ? 0 : 1);
|
||||
modifiedBib = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!modifiedFee.empty() && oe->getNumRunners() > 0) {
|
||||
bool updateFee = gdi.ask(L"ask:changedclassfee");
|
||||
|
||||
@ -3724,10 +3754,18 @@ void TabClass::prepareForDrawing(gdioutput &gdi) {
|
||||
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Bib)) {
|
||||
gdi.fillRight();
|
||||
gdi.addString("", 0, "Antal reserverade nummerlappsnummer mellan klasser:");
|
||||
gdi.dropLine(-0.1);
|
||||
gdi.dropLine(-0.2);
|
||||
gdi.addInput("BibGap", itow(oe->getBibClassGap()), 5);
|
||||
|
||||
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Vacancy)) {
|
||||
bool bibToVacant = oe->getDCI().getInt("NoVacantBib") == 0;
|
||||
gdi.dropLine(0.2);
|
||||
gdi.setCX(gdi.getCX() + gdi.scaleLength(15));
|
||||
gdi.addCheckbox("VacantBib", "Tilldela nummerlapp till vakanter", nullptr, bibToVacant);
|
||||
}
|
||||
|
||||
gdi.popX();
|
||||
gdi.dropLine(1.5);
|
||||
gdi.dropLine(2.4);
|
||||
gdi.fillDown();
|
||||
}
|
||||
|
||||
@ -3868,7 +3906,15 @@ void TabClass::drawDialog(gdioutput &gdi, oEvent::DrawMethod method, const oClas
|
||||
gdi.addCheckbox("HandleBibs", "Tilldela nummerlappar:", ClassesCB, lastHandleBibs).setSynchData(&lastHandleBibs);
|
||||
gdi.dropLine(-0.2);
|
||||
gdi.addInput("Bib", L"", 10, 0, L"", L"Mata in första nummerlappsnummer, eller blankt för att ta bort nummerlappar");
|
||||
gdi.setInputStatus("Bib", lastHandleBibs);
|
||||
|
||||
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Vacancy)) {
|
||||
bool bibToVacant = oe->getDCI().getInt("NoVacantBib") == 0;
|
||||
gdi.dropLine(0.2);
|
||||
gdi.addCheckbox("VacantBib", "Tilldela nummerlapp till vakanter", nullptr, bibToVacant);
|
||||
gdi.setInputStatus("VacantBib", lastHandleBibs);
|
||||
}
|
||||
|
||||
gdi.setInputStatus("Bib", lastHandleBibs);
|
||||
gdi.fillDown();
|
||||
gdi.dropLine(2.5);
|
||||
gdi.popX();
|
||||
@ -3968,6 +4014,7 @@ void TabClass::setMultiDayClass(gdioutput &gdi, bool hasMulti, oEvent::DrawMetho
|
||||
if (hasMulti) {
|
||||
gdi.check("HandleBibs", false);
|
||||
gdi.setInputStatus("Bib", false);
|
||||
gdi.setInputStatus("VacantBib", false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -636,7 +636,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
|
||||
ListBoxInfo lbi;
|
||||
bool advancedResults = false;
|
||||
if (gdi.getSelectedItem("ListType", lbi)) {
|
||||
currentListType=EStdListType(lbi.data);
|
||||
currentListType = EStdListType(lbi.data);
|
||||
}
|
||||
else if (gdi.getSelectedItem("ResultType", lbi)) {
|
||||
currentListType = getTypeFromResultIndex(lbi.data);
|
||||
@ -1230,6 +1230,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
|
||||
else if (lbi.id == "ListSelection") {
|
||||
gdi.getSelection(lbi.id, lastClassSelection);
|
||||
if (gdi.hasWidget("ResultType")) {
|
||||
lastResultClassSelection = lastClassSelection;
|
||||
ListBoxInfo entry;
|
||||
gdi.getSelectedItem("ResultType", entry);
|
||||
gdi.setInputStatus("Generate", !lastClassSelection.empty() && int(entry.data) >= 0);
|
||||
@ -3010,8 +3011,7 @@ void TabList::setResultOptionsFromType(gdioutput &gdi, int data) {
|
||||
|
||||
gdi.setInputStatus("ShowInterResults", builtIn);
|
||||
gdi.setInputStatus("ShowSplits", builtIn);
|
||||
|
||||
|
||||
|
||||
set<int> clsUnused;
|
||||
vector< pair<wstring, size_t> > out;
|
||||
|
||||
@ -3022,22 +3022,14 @@ void TabList::setResultOptionsFromType(gdioutput &gdi, int data) {
|
||||
if (!out.empty() && lastLeg >= 0)
|
||||
gdi.selectItemByData("LegNumber", lastLeg);
|
||||
|
||||
//oe->fillLegNumbers(gdi, "LegNumber", li.isTeamList(), true);
|
||||
gdi.setInputStatus("InputNumber", false);
|
||||
}
|
||||
else {
|
||||
|
||||
else {
|
||||
gdi.setInputStatus("UseLargeSize", li.supportLarge);
|
||||
gdi.setInputStatus("InputNumber", li.supportParameter);
|
||||
|
||||
//gdi.setInputStatus("SplitAnalysis", li.supportSplitAnalysis);
|
||||
//gdi.setInputStatus("ShowInterResults", li.supportInterResults);
|
||||
//gdi.setInputStatus("PageBreak", li.supportPageBreak);
|
||||
//gdi.setInputStatus("ClassLimit", li.supportClassLimit);
|
||||
|
||||
if (li.supportLegs) {
|
||||
gdi.enableInput("LegNumber");
|
||||
//oe->fillLegNumbers(gdi, "LegNumber", li.isTeamList(), true);
|
||||
set<int> clsUnused;
|
||||
vector< pair<wstring, size_t> > out;
|
||||
oe->fillLegNumbers(clsUnused, li.isTeamList(), true, out);
|
||||
@ -3095,12 +3087,19 @@ void TabList::setResultOptionsFromType(gdioutput &gdi, int data) {
|
||||
gdi.setSelection("ListSelection", lastResultClassSelection);
|
||||
}
|
||||
|
||||
gdi.setInputStatus("Generate", data >= 0 && !lastResultClassSelection.empty());
|
||||
gdi.setInputStatus("Generate", data >= 0 && hasSelectedClass(gdi));
|
||||
}
|
||||
|
||||
bool TabList::hasSelectedClass(gdioutput& gdi) {
|
||||
set<int> sel;
|
||||
gdi.getSelection("ListSelection", sel);
|
||||
return !sel.empty();
|
||||
}
|
||||
|
||||
void TabList::clearCompetitionData() {
|
||||
SelectedList = "";
|
||||
lastResultClassSelection.clear();
|
||||
lastClassSelection.clear();
|
||||
|
||||
ownWindow = false;
|
||||
hideButtons = false;
|
||||
|
||||
@ -49,6 +49,8 @@ protected:
|
||||
|
||||
static void createListButtons(gdioutput &gdi);
|
||||
|
||||
static bool hasSelectedClass(gdioutput& gdi);
|
||||
|
||||
void generateList(gdioutput &gdi, bool forceUpdate = false);
|
||||
void selectGeneralList(gdioutput &gdi, EStdListType type);
|
||||
|
||||
|
||||
@ -207,8 +207,8 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
|
||||
vector<int> delta;
|
||||
vector<int> place;
|
||||
vector<int> after;
|
||||
vector<int> placeAcc;
|
||||
vector<int> afterAcc;
|
||||
vector<oRunner::ResultData> placeAcc;
|
||||
vector<oRunner::ResultData> afterAcc;
|
||||
|
||||
r->getSplitAnalysis(delta);
|
||||
r->getLegTimeAfter(after);
|
||||
@ -221,13 +221,13 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
|
||||
for (size_t k = 0; k < delta.size(); k++) {
|
||||
out += itow(place[k]);
|
||||
if (k < placeAcc.size())
|
||||
out += L" (" + itow(placeAcc[k]) + L")";
|
||||
out += L" (" + itow(placeAcc[k].get(false)) + L")";
|
||||
|
||||
if (after[k] > 0)
|
||||
out += L" +" + formatTimeMS(after[k], false);
|
||||
|
||||
if (k < afterAcc.size() && afterAcc[k]>0)
|
||||
out += L" (+" + formatTimeMS(afterAcc[k], false) + L")";
|
||||
if (k < afterAcc.size() && afterAcc[k].get(false)>0)
|
||||
out += L" (+" + formatTimeMS(afterAcc[k].get(false), false) + L")";
|
||||
|
||||
if (delta[k] > 0)
|
||||
out += L" B: " + formatTimeMS(delta[k], false);
|
||||
@ -463,7 +463,7 @@ int TabRunner::searchCB(gdioutput &gdi, int type, void *data) {
|
||||
|
||||
bool formMode = currentMode == 0;
|
||||
|
||||
vector< pair<wstring, size_t> > runners;
|
||||
vector<pair<wstring, size_t>> runners;
|
||||
oe->fillRunners(runners, !formMode, formMode ? 0 : oEvent::RunnerFilterShowAll, filter);
|
||||
|
||||
if (filter.size() == runners.size()){
|
||||
@ -813,6 +813,15 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
|
||||
else if (bi.id == "ListenReadout") {
|
||||
listenToPunches = gdi.isChecked(bi.id);
|
||||
}
|
||||
else if (bi.id == "HideControls") {
|
||||
hideReportControls = true;
|
||||
listenToPunches = true;
|
||||
PostMessage(gdi.getHWNDTarget(), WM_USER + 2, TRunnerTab, 0);
|
||||
}
|
||||
/*else if (bi.id == "ShowReportHeader") {
|
||||
showReportHeader = gdi.isChecked(bi.id);
|
||||
PostMessage(gdi.getHWNDTarget(), WM_USER + 2, TRunnerTab, 0);
|
||||
}*/
|
||||
else if (bi.id=="Unpair") {
|
||||
ListBoxInfo lbi;
|
||||
int cid = bi.getExtraInt();
|
||||
@ -1225,7 +1234,14 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
|
||||
return 0;
|
||||
}
|
||||
runnerId = bi.data;
|
||||
//loadPage(gdi);
|
||||
PostMessage(gdi.getHWNDTarget(), WM_USER + 2, TRunnerTab, 0);
|
||||
}
|
||||
else if (bi.id == "NumCols") {
|
||||
numReportColumn = bi.data;
|
||||
PostMessage(gdi.getHWNDTarget(), WM_USER + 2, TRunnerTab, 0);
|
||||
}
|
||||
else if (bi.id == "NumRows") {
|
||||
numReportRow = bi.data;
|
||||
PostMessage(gdi.getHWNDTarget(), WM_USER + 2, TRunnerTab, 0);
|
||||
}
|
||||
else if (bi.id=="RClass") {
|
||||
@ -1322,24 +1338,20 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
cellAction(gdi, ei.getData(), b);
|
||||
}
|
||||
else if ((ei.id == "DataUpdate") && listenToPunches && currentMode == 5) {
|
||||
if (ei.getData() > 0) {
|
||||
runnerId = ei.getData();
|
||||
else if (currentMode == 5 && ei.id == "PunchCard") {
|
||||
if (listenToPunches && ei.getData() > 0) {
|
||||
addToReport(ei.getData(), true);
|
||||
|
||||
loadPage(gdi);
|
||||
}
|
||||
loadPage(gdi);
|
||||
}
|
||||
else if ((ei.id == "ReadCard") &&
|
||||
(listenToPunches || oe->isReadOnly()) && currentMode == 5) {
|
||||
if (ei.getData() > 0) {
|
||||
vector<pRunner> rs;
|
||||
oe->getRunnersByCardNo(ei.getData(), true, oEvent::CardLookupProperty::Any, rs);
|
||||
if (!rs.empty()) {
|
||||
runnersToReport.resize(rs.size());
|
||||
for (size_t k = 0; k<rs.size(); k++)
|
||||
runnersToReport[k] = make_pair(rs[k]->getId(), false);
|
||||
}
|
||||
runnerId = 0;
|
||||
}
|
||||
else if (currentMode == 5 && ei.id == "DataUpdate" && currentMode == 5) {
|
||||
showRunnerReport(gdi);
|
||||
}
|
||||
else if (currentMode == 5 && ei.id == "ReadCard" &&
|
||||
(listenToPunches || oe->isReadOnly())) {
|
||||
if (ei.getData() > 0)
|
||||
addToReport(ei.getData(), oe->isReadOnly());
|
||||
loadPage(gdi);
|
||||
}
|
||||
}
|
||||
@ -1610,127 +1622,392 @@ void TabRunner::setCardNo(gdioutput &gdi, int cardNo) {
|
||||
}
|
||||
}
|
||||
|
||||
string TabRunner::computeKeyForReport() {
|
||||
string key = itos(runnersToReport.size());
|
||||
for (auto &id : runnersToReport) {
|
||||
key += "|" + itos(id.first);
|
||||
pRunner r = oe->getRunner(id.first, 0);
|
||||
if (r) {
|
||||
key += gdioutput::toUTF8(r->getCompleteIdentification() + r->getClass(true));
|
||||
key += itos(r->getStatus()) + itos(r->getFinishTime()) + itos(r->getStartTime());
|
||||
vector<pFreePunch> pl;
|
||||
oe->getPunchesForRunner(id.first, true, pl);
|
||||
for (auto p : pl)
|
||||
key += itos(p->getTimeInt());
|
||||
|
||||
if (r->getCard()) {
|
||||
auto ch = r->getCard()->getCardHash();
|
||||
key += itos(ch.first) + itos(ch.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
void TabRunner::showRunnerReport(gdioutput &gdi) {
|
||||
string oldHash, newHash = computeKeyForReport();
|
||||
|
||||
if (gdi.getData("ReportHash", oldHash) && oldHash == newHash)
|
||||
return;
|
||||
|
||||
gdi.clearPage(true);
|
||||
gdi.setData("ReportHash", newHash);
|
||||
currentMode = 5;
|
||||
|
||||
if (!ownWindow && !oe->isReadOnly())
|
||||
addToolbar(gdi);
|
||||
else if (oe->isReadOnly())
|
||||
else if (oe->isReadOnly() && !listenToPunches)
|
||||
gdi.addString("", fontLarge, makeDash(L"MeOS - Resultatkiosk")).setColor(colorDarkBlue);
|
||||
|
||||
gdi.dropLine();
|
||||
if (!hideReportControls) {
|
||||
bool any = false;
|
||||
gdi.pushX();
|
||||
gdi.fillRight();
|
||||
|
||||
gdi.pushX();
|
||||
gdi.fillRight();
|
||||
|
||||
gdi.addSelection("ReportRunner", 300, 300, RunnerCB);
|
||||
oe->fillRunners(gdi, "ReportRunner", true, oEvent::RunnerFilterShowAll | oEvent::RunnerCompactMode);
|
||||
gdi.selectItemByData("ReportRunner", runnerId);
|
||||
|
||||
if (!oe->isReadOnly()) {
|
||||
if (!ownWindow) {
|
||||
gdi.addButton("Kiosk", "Resultatkiosk", RunnerCB);
|
||||
gdi.addButton("Window", "Eget fönster", RunnerCB, "Öppna i ett nytt fönster.");
|
||||
if (!oe->isReadOnly() || !listenToPunches) {
|
||||
gdi.dropLine();
|
||||
gdi.addSelection("ReportRunner", 300, 300, RunnerCB);
|
||||
oe->fillRunners(gdi, "ReportRunner", true, oEvent::RunnerFilterShowAll | oEvent::RunnerCompactMode);
|
||||
gdi.selectItemByData("ReportRunner", runnerId);
|
||||
gdi.autoGrow("ReportRunner");
|
||||
any = true;
|
||||
}
|
||||
gdi.dropLine(0.2);
|
||||
gdi.addCheckbox("ListenReadout", "Visa senast inlästa deltagare", RunnerCB, listenToPunches);
|
||||
}
|
||||
|
||||
gdi.dropLine(3);
|
||||
if (!oe->isReadOnly() && !hideReportControls) {
|
||||
if (!ownWindow) {
|
||||
gdi.addButton("Kiosk", "Resultatkiosk", RunnerCB);
|
||||
gdi.addButton("Window", "Eget fönster", RunnerCB, "Öppna i ett nytt fönster.");
|
||||
}
|
||||
else {
|
||||
gdi.addButton("HideControls", "Dölj inställningar", RunnerCB);
|
||||
}
|
||||
|
||||
any = true;
|
||||
gdi.dropLine(0.2);
|
||||
gdi.addCheckbox("ListenReadout", "Visa senast inlästa deltagare", RunnerCB, listenToPunches);
|
||||
gdi.dropLine(2);
|
||||
gdi.popX();
|
||||
vector<pair<wstring, size_t>> options;
|
||||
for (int i = 1; i <= 10; i++)
|
||||
options.emplace_back(itow(i), i);
|
||||
|
||||
gdi.addString("", 0, "Layout");
|
||||
|
||||
gdi.addSelection("NumRows", 100, 200, RunnerCB);
|
||||
gdi.addString("", 0, "rader");
|
||||
gdi.addItem("NumRows", options);
|
||||
gdi.selectItemByData("NumRows", numReportRow);
|
||||
|
||||
gdi.addSelection("NumCols", 100, 200, RunnerCB);
|
||||
gdi.addString("", 0, "kolumner");
|
||||
gdi.addItem("NumCols", options);
|
||||
gdi.selectItemByData("NumCols", numReportColumn);
|
||||
|
||||
//gdi.addCheckbox("ShowReportHeader", "Visa sidhuvud", RunnerCB);
|
||||
}
|
||||
|
||||
if (any)
|
||||
gdi.dropLine(3);
|
||||
}
|
||||
gdi.popX();
|
||||
gdi.registerEvent("DataUpdate", RunnerCB);
|
||||
gdi.registerEvent("ReadCard", RunnerCB);
|
||||
|
||||
if (runnerId > 0) {
|
||||
runnersToReport.resize(1);
|
||||
runnersToReport[0] = make_pair(runnerId, false);
|
||||
}
|
||||
generateRunnerReport(*oe, gdi, runnersToReport);
|
||||
gdi.registerEvent("PunchCard", RunnerCB);
|
||||
gdi.setData("DataSync", 1);
|
||||
gdi.setData("PunchSync", 1);
|
||||
|
||||
if (runnersToReport.size() == 1)
|
||||
if (runnerId > 0) {
|
||||
bool found = false;
|
||||
addToReport(runnerId);
|
||||
}
|
||||
while (runnersToReport.size() > numReportRow * numReportColumn)
|
||||
runnersToReport.pop_back();
|
||||
|
||||
generateRunnerReport(*oe, gdi, numReportColumn, numReportRow, true, runnersToReport);
|
||||
|
||||
if (runnersToReport.size() > 0)
|
||||
runnerId = runnersToReport[0].first;
|
||||
}
|
||||
|
||||
void TabRunner::generateRunnerReport(oEvent &oe, gdioutput &gdi, vector<pair<int, bool>> &runnersToReport) {
|
||||
oe.synchronizeList({ oListId::oLRunnerId, oListId::oLTeamId, oListId::oLPunchId });
|
||||
gdi.fillDown();
|
||||
void TabRunner::addToReport(int id) {
|
||||
bool found = false;
|
||||
for (auto& rr : runnersToReport) {
|
||||
if (rr.first == id)
|
||||
found = true;
|
||||
}
|
||||
if (!found) {
|
||||
runnersToReport.emplace_front(id, false);
|
||||
}
|
||||
}
|
||||
|
||||
cTeam t = 0;
|
||||
void TabRunner::addToReport(int cardNo, bool punchForShowReport) {
|
||||
vector<pRunner> rs;
|
||||
oe->getRunnersByCardNo(cardNo, true, oEvent::CardLookupProperty::Any, rs);
|
||||
|
||||
if (!punchForShowReport) {
|
||||
// Take away runners with no card
|
||||
vector<pRunner> rsFilter;
|
||||
for (pRunner r : rs) {
|
||||
if (r->getCard())
|
||||
rsFilter.push_back(r);
|
||||
}
|
||||
rs.swap(rsFilter);
|
||||
}
|
||||
|
||||
if (!rs.empty()) {
|
||||
if (rs.size() == 1) {
|
||||
addToReport(rs[0]->getId());
|
||||
}
|
||||
else {
|
||||
map<int, vector<pRunner>> runnersPerTeam;
|
||||
for (pRunner r : rs) {
|
||||
if (r->getTeam())
|
||||
runnersPerTeam[r->getTeam()->getId()].push_back(r);
|
||||
else
|
||||
runnersPerTeam[0].push_back(r);
|
||||
}
|
||||
|
||||
for (auto& rpt : runnersPerTeam) {
|
||||
if (rpt.second.size() == 1) {
|
||||
addToReport(rpt.second[0]->getId());
|
||||
}
|
||||
else if (rpt.first == 0) {
|
||||
sort(rpt.second.begin(), rpt.second.end(),
|
||||
[](const pRunner& a, const pRunner& b) {return unsigned(a->getStartTime() - 1) < unsigned(b->getStartTime() - 1); });
|
||||
// Take the last competitor using the card
|
||||
addToReport(rpt.second.back()->getId());
|
||||
}
|
||||
else {
|
||||
sort(rpt.second.begin(), rpt.second.end(),
|
||||
[](const pRunner& a, const pRunner& b) {return a->getLegNumber() < b->getLegNumber(); });
|
||||
bool hasResultAny = false;
|
||||
bool done = false;
|
||||
for (pRunner r : rpt.second) {
|
||||
if (r->hasFinished())
|
||||
hasResultAny = true;
|
||||
else if (hasResultAny) {
|
||||
// Prefer to report the next runner to run
|
||||
addToReport(r->getId());
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!done) {
|
||||
if (hasResultAny) {
|
||||
// Take the last one (final result)
|
||||
addToReport(rpt.second.back()->getId());
|
||||
}
|
||||
else {
|
||||
// None finished. Take first
|
||||
addToReport(rpt.second.front()->getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*runnersToReport.resize(rs.size());
|
||||
for (size_t k = 0; k<rs.size(); k++)
|
||||
runnersToReport[k] = make_pair(rs[k]->getId(), false);*/
|
||||
}
|
||||
runnerId = 0;
|
||||
}
|
||||
|
||||
|
||||
void TabRunner::generateRunnerReport(oEvent &oe, gdioutput &gdi,
|
||||
int numX, int numY,
|
||||
bool onlySelectedRunner,
|
||||
const deque<pair<int, bool>> &runnersToReport) {
|
||||
oe.synchronizeList({ oListId::oLRunnerId, oListId::oLTeamId, oListId::oLPunchId });
|
||||
gdi.fillDown();
|
||||
int xx, yy;
|
||||
int margin = gdi.scaleLength(16);
|
||||
gdi.getTargetDimension(xx, yy);
|
||||
|
||||
int maxWidth = max(gdi.scaleLength(130 * 3) + 2*margin, xx / numX - margin * (numX + 1));
|
||||
if (numX == 1 && numY == 1)
|
||||
maxWidth = min(maxWidth, gdi.scaleLength(130)*6+margin);
|
||||
|
||||
bool frame = true;
|
||||
|
||||
vector<const oTeam *> tList;
|
||||
set<int> clsSet;
|
||||
|
||||
for (size_t k = 0; k < runnersToReport.size(); k++) {
|
||||
pRunner r = oe.getRunner(runnersToReport[k].first, 0);
|
||||
if (!r)
|
||||
continue;
|
||||
clsSet.insert(r->getClassId(true));
|
||||
if (r && r->getTeam()) {
|
||||
pTeam t = r->getTeam();
|
||||
if (t) {
|
||||
pClass cls = r->getClassRef(true);
|
||||
if (cls && cls->getClassType() != oClassRelay)
|
||||
continue;
|
||||
|
||||
if (t == 0)
|
||||
t = r->getTeam();
|
||||
bool added = count(tList.begin(), tList.end(), t) > 0;
|
||||
if (added)
|
||||
continue;
|
||||
tList.push_back(t);
|
||||
}
|
||||
}
|
||||
oe.calculateResults(clsSet, oEvent::ResultType::PreliminarySplitResults, true);
|
||||
oe.calculateResults(clsSet, oEvent::ResultType::ClassResult);
|
||||
|
||||
if (t == 0) {
|
||||
for (size_t k = 0; k < runnersToReport.size(); k++)
|
||||
runnerReport(oe, gdi, runnersToReport[k].first, runnersToReport[k].second);
|
||||
}
|
||||
else {
|
||||
oe.calculateTeamResults(clsSet, oEvent::ResultType::ClassResult);
|
||||
RECT rcFrame;
|
||||
|
||||
auto drawBox = [&gdi](RECT &rcFrame) {
|
||||
RECT rc = rcFrame;
|
||||
int mg = gdi.scaleLength(5);
|
||||
rc.left -= mg;
|
||||
rc.top -= mg;
|
||||
rc.right += mg;
|
||||
rc.bottom += mg;
|
||||
gdi.addRectangle(rc, GDICOLOR::colorLightCyan, true, true);
|
||||
};
|
||||
|
||||
set<int> selectedRunners;
|
||||
bool selHasRes = false;
|
||||
for (size_t k = 0; k < runnersToReport.size(); k++) {
|
||||
selectedRunners.insert(runnersToReport[k].first);
|
||||
pRunner r = oe.getRunner(runnersToReport[k].first, 0);
|
||||
if (r && r->hasOnCourseResult())
|
||||
selHasRes = true;
|
||||
}
|
||||
int baseX = gdi.getCX();
|
||||
int baseY = gdi.getCY();
|
||||
vector<RECT> rcList;
|
||||
|
||||
wstring tInfo = t->getName();
|
||||
if (t->statusOK(true, true)) {
|
||||
tInfo += L", " + t->getRunningTimeS(true, SubSecond::Auto) + lang.tl(", Placering: ") + t->getPlaceS();
|
||||
if (t->getTimeAfter(-1, true) > 0)
|
||||
tInfo += L", +" + formatTime(t->getTimeAfter(-1, true));
|
||||
}
|
||||
else if (t->getStatusComputed(true) != StatusUnknown) {
|
||||
tInfo += L" " + t->getStatusS(true, true);
|
||||
}
|
||||
auto updatePositionDrawBox = [&](bool force) {
|
||||
if (!force)
|
||||
rcList.push_back(rcFrame);
|
||||
|
||||
gdi.addStringUT(fontMediumPlus, t->getClass(true));
|
||||
gdi.addStringUT(boldLarge, tInfo);
|
||||
gdi.dropLine();
|
||||
|
||||
bool visitedSelected = false;
|
||||
for (int leg = 0; leg < t->getNumRunners(); leg++) {
|
||||
if (selHasRes && visitedSelected)
|
||||
break;
|
||||
|
||||
pRunner r = t->getRunner(leg);
|
||||
pRunner nextR = t->getRunner(leg + 1);
|
||||
bool nextSelected = nextR && selectedRunners.count(nextR->getId());
|
||||
|
||||
if (r) {
|
||||
bool selected = selectedRunners.count(r->getId()) > 0;
|
||||
|
||||
if (selHasRes) {
|
||||
runnerReport(oe, gdi, r->getId(), !selected);
|
||||
}
|
||||
else {
|
||||
runnerReport(oe, gdi, r->getId(), !nextSelected);
|
||||
}
|
||||
|
||||
visitedSelected |= selected;
|
||||
if ((force && !rcList.empty()) || rcList.size() == numX) {
|
||||
int maxYP = 0;
|
||||
for (RECT& rc : rcList)
|
||||
maxYP = max<int>(maxYP, rc.bottom);
|
||||
for (RECT& rc : rcList) {
|
||||
rc.bottom = maxYP;
|
||||
drawBox(rc);
|
||||
}
|
||||
rcList.clear();
|
||||
baseY = maxYP + margin;
|
||||
}
|
||||
|
||||
gdi.setCY(baseY);
|
||||
gdi.setCX(baseX + (maxWidth + margin) * rcList.size());
|
||||
};
|
||||
|
||||
for (size_t k = 0; k < runnersToReport.size(); k++) {
|
||||
pRunner r = oe.getRunner(runnersToReport[k].first, 0);
|
||||
if (!r)
|
||||
continue;
|
||||
|
||||
if (count(tList.begin(), tList.end(), r->getTeam()) == 0) {
|
||||
runnerReport(oe, gdi, runnersToReport[k].first, runnersToReport[k].second, maxWidth, rcFrame);
|
||||
updatePositionDrawBox(false);
|
||||
}
|
||||
}
|
||||
if (tList.size() > 0) {
|
||||
oe.calculateTeamResults(clsSet, oEvent::ResultType::ClassResult);
|
||||
for (const oTeam *t : tList) {
|
||||
teamReport(oe, gdi, t, onlySelectedRunner, runnersToReport, maxWidth, rcFrame);
|
||||
updatePositionDrawBox(false);
|
||||
}
|
||||
}
|
||||
|
||||
updatePositionDrawBox(true);
|
||||
}
|
||||
|
||||
void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
|
||||
void TabRunner::teamReport(oEvent& oe, gdioutput& gdi,
|
||||
const oTeam* t,
|
||||
bool onlySelectedRunner,
|
||||
const deque<pair<int, bool>>& runnersToReport,
|
||||
int maxWidth,
|
||||
RECT& rc) {
|
||||
rc.top = gdi.getCY();
|
||||
rc.left = gdi.getCX();
|
||||
rc.right = rc.left + maxWidth;
|
||||
|
||||
set<int> selectedRunners;
|
||||
bool selHasPartialRes = false;
|
||||
for (size_t k = 0; k < runnersToReport.size(); k++) {
|
||||
pRunner r = oe.getRunner(runnersToReport[k].first, 0);
|
||||
if (r && r->getTeam() == t) {
|
||||
selectedRunners.insert(runnersToReport[k].first);
|
||||
if (r && r->hasOnCourseResult())
|
||||
selHasPartialRes = true; //Partial (radio) or complete result
|
||||
}
|
||||
}
|
||||
|
||||
wstring tInfo = t->getName();
|
||||
if (t->statusOK(true, true)) {
|
||||
tInfo += L", " + t->getRunningTimeS(true, SubSecond::Auto) + lang.tl(", Placering: ") + t->getPlaceS();
|
||||
if (t->getTimeAfter(-1, true) > 0)
|
||||
tInfo += L", +" + formatTime(t->getTimeAfter(-1, true));
|
||||
}
|
||||
else if (t->getStatusComputed(true) != StatusUnknown) {
|
||||
tInfo += L" " + t->getStatusS(true, true);
|
||||
}
|
||||
|
||||
gdi.addStringUT(fontMediumPlus, t->getClass(true));
|
||||
gdi.addStringUT(boldLarge, tInfo);
|
||||
gdi.dropLine();
|
||||
|
||||
pClass cls = t->getClassRef(false);
|
||||
|
||||
bool visitedSelected = false;
|
||||
for (int leg = 0; leg < t->getNumRunners(); leg++) {
|
||||
if ((selHasPartialRes || onlySelectedRunner) && visitedSelected)
|
||||
break;
|
||||
|
||||
pRunner r = t->getRunner(leg);
|
||||
|
||||
pRunner nextR = t->getRunner(leg + 1);
|
||||
bool nextSelected = false;
|
||||
if (cls) {
|
||||
// Check if leg has the selected runner (parallel legs)
|
||||
int legNr, legOrd;
|
||||
cls->splitLegNumberParallel(leg, legNr, legOrd);
|
||||
int nextLeg = leg;
|
||||
while (++nextLeg < t->getNumRunners()) {
|
||||
int legNrN, legOrdN;
|
||||
cls->splitLegNumberParallel(leg, legNrN, legOrdN);
|
||||
if (legNrN == legNr + 1) {
|
||||
nextR = t->getRunner(nextLeg);
|
||||
nextSelected = nextR && selectedRunners.count(nextR->getId());
|
||||
if (nextSelected)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
nextSelected = nextR && selectedRunners.count(nextR->getId());
|
||||
}
|
||||
|
||||
if (r) {
|
||||
bool selected = selectedRunners.count(r->getId()) > 0;
|
||||
|
||||
if (onlySelectedRunner && !selected) {
|
||||
if (!nextSelected)
|
||||
continue; // Always skip if next is not selected
|
||||
if (nextR->hasResult())
|
||||
continue; // Only include previous if next does not have results
|
||||
}
|
||||
RECT dmy;
|
||||
if (selHasPartialRes) {
|
||||
// The selected runner has some result. Focus on that
|
||||
runnerReport(oe, gdi, r->getId(), !selected, maxWidth, dmy);
|
||||
}
|
||||
else {
|
||||
// The selected runner has not started. Focus on previous result
|
||||
runnerReport(oe, gdi, r->getId(), !nextSelected, maxWidth, dmy);
|
||||
}
|
||||
|
||||
visitedSelected |= selected;
|
||||
}
|
||||
}
|
||||
rc.bottom = gdi.getCY();
|
||||
}
|
||||
|
||||
void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi,
|
||||
int id, bool compact,
|
||||
int maxWidth, RECT &rc) {
|
||||
|
||||
rc.top = gdi.getCY();
|
||||
rc.left = gdi.getCX();
|
||||
rc.right = rc.left + maxWidth;
|
||||
|
||||
pRunner r = oe.getRunner(id, 0);
|
||||
if (!r || ! r->getClassRef(false))
|
||||
return;
|
||||
@ -1739,7 +2016,8 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
|
||||
gdi.fillDown();
|
||||
if (r->getTeam() == 0) {
|
||||
gdi.addStringUT(fontMediumPlus, r->getClass(true));
|
||||
gdi.addStringUT(boldLarge, r->getCompleteIdentification());
|
||||
gdi.addStringUT(gdi.getCY(), gdi.getCX(), boldLarge,
|
||||
r->getCompleteIdentification(), maxWidth - 4);
|
||||
}
|
||||
else {
|
||||
wstring s;
|
||||
@ -1784,20 +2062,31 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
|
||||
|
||||
gdi.popX();
|
||||
gdi.fillRight();
|
||||
int ww = gdi.scaleLength(120);
|
||||
auto optionalBreakLine = [&] {
|
||||
if (gdi.getCX() + ww > rc.left + maxWidth) {
|
||||
gdi.popX();
|
||||
gdi.dropLine();
|
||||
}
|
||||
};
|
||||
|
||||
if (r->getStartTime() > 0)
|
||||
if (r->getStartTime() > 0) {
|
||||
optionalBreakLine();
|
||||
gdi.addString("", fontMedium, L"Starttid: X #" + r->getStartTimeCompact());
|
||||
|
||||
if (r->getFinishTime() > 0)
|
||||
}
|
||||
if (r->getFinishTime() > 0) {
|
||||
optionalBreakLine();
|
||||
gdi.addString("", fontMedium, L"Måltid: X #" + r->getFinishTimeS(false, SubSecond::Auto));
|
||||
|
||||
}
|
||||
const wstring &after = oe.formatListString(lRunnerTimeAfter, r);
|
||||
if (!after.empty()) {
|
||||
optionalBreakLine();
|
||||
gdi.addString("", fontMedium, L"Tid efter: X #" + after);
|
||||
}
|
||||
|
||||
const wstring &lost = oe.formatListString(lRunnerLostTime, r);
|
||||
if (!lost.empty()) {
|
||||
optionalBreakLine();
|
||||
gdi.addString("", fontMedium, L"Bomtid: X #" + lost).setColor(colorDarkRed);
|
||||
}
|
||||
|
||||
@ -1813,17 +2102,28 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
|
||||
int xp = gdi.getCX();
|
||||
int yp = gdi.getCY();
|
||||
int xw = gdi.scaleLength(130);
|
||||
int cx = xp;
|
||||
int mg4 = gdi.scaleLength(4);
|
||||
int cx = xp + mg4;
|
||||
int limit = (9*xw)/10;
|
||||
int lh = gdi.getLineHeight();
|
||||
int maxTimesPerLine = min(10, max(3, maxWidth / xw));
|
||||
|
||||
auto drawBox = [&gdi, xw, mg4, lh](int yp, int cx, GDICOLOR color) {
|
||||
RECT rc;
|
||||
rc.top = yp - mg4 / 2;
|
||||
rc.bottom = yp + lh * 5 - mg4;
|
||||
rc.left = cx - mg4;
|
||||
rc.right = cx + xw - mg4 * 2;
|
||||
gdi.addRectangle(rc, color);
|
||||
};
|
||||
|
||||
if (crs && r->getStatus() != StatusUnknown) {
|
||||
int nc = crs->getNumControls();
|
||||
vector<int> delta;
|
||||
vector<int> place;
|
||||
vector<int> after;
|
||||
vector<int> placeAcc;
|
||||
vector<int> afterAcc;
|
||||
vector<oRunner::ResultData> placeAcc;
|
||||
vector<oRunner::ResultData> afterAcc;
|
||||
|
||||
r->getSplitAnalysis(delta);
|
||||
r->getLegTimeAfter(after);
|
||||
@ -1844,7 +2144,7 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
|
||||
else
|
||||
gdi.addStringUT(yp, cx, boldText, name, limit);
|
||||
|
||||
wstring split = r->getSplitTimeS(k, false);
|
||||
wstring split = r->getSplitTimeS(k, false, SubSecond::Off);
|
||||
|
||||
int bestTime = 0;
|
||||
if ( k < int(after.size()) && after[k] >= 0)
|
||||
@ -1865,14 +2165,14 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
|
||||
gdi.addStringUT(yp + lh, cx, fontMedium, split, limit);
|
||||
|
||||
if (k>0 && k < int(placeAcc.size())) {
|
||||
split = r->getPunchTimeS(k, false, false, SubSecond::Auto);
|
||||
wstring pl = placeAcc[k] > 0 ? itow(placeAcc[k]) : L"-";
|
||||
split = r->getPunchTimeS(k, false, false, false, SubSecond::Auto);
|
||||
wstring pl = placeAcc[k].get(false) > 0 ? itow(placeAcc[k].get(false)) : L"-";
|
||||
if (k < int(afterAcc.size()) ) {
|
||||
if (afterAcc[k] > 0)
|
||||
split += L" (" + pl + L", +" + formatTimeMS(afterAcc[k], false) + L")";
|
||||
else if (placeAcc[k] == 1)
|
||||
if (afterAcc[k].get(false) > 0)
|
||||
split += L" (" + pl + L", +" + formatTimeMS(afterAcc[k].get(false), false) + L")";
|
||||
else if (placeAcc[k].get(false) == 1)
|
||||
split += lang.tl(" (ledare)");
|
||||
else if (placeAcc[k] > 0)
|
||||
else if (placeAcc[k].get(false) > 0)
|
||||
split += L" " + pl;
|
||||
}
|
||||
gdi.addStringUT(yp + 2*lh, cx, fontMedium, split, limit).setColor(colorDarkBlue);
|
||||
@ -1885,18 +2185,10 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
|
||||
colorMediumDarkRed : colorMediumRed;
|
||||
}
|
||||
|
||||
RECT rc;
|
||||
rc.top = yp - 2;
|
||||
rc.bottom = yp + lh*5 - 4;
|
||||
rc.left = cx - 4;
|
||||
rc.right = cx + xw - 8;
|
||||
|
||||
gdi.addRectangle(rc, color);
|
||||
|
||||
drawBox(yp, cx, color);
|
||||
cx += xw;
|
||||
|
||||
if (k % 6 == 5) {
|
||||
cx = xp;
|
||||
if ( (k+1) % maxTimesPerLine == 0) {
|
||||
cx = xp + mg4;
|
||||
yp += lh * 5;
|
||||
}
|
||||
}
|
||||
@ -1950,26 +2242,19 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
|
||||
|
||||
GDICOLOR color = colorDefault;
|
||||
|
||||
RECT rc;
|
||||
rc.top = yp - 2;
|
||||
rc.bottom = yp + lh*5 - 4;
|
||||
rc.left = cx - 4;
|
||||
rc.right = cx + xw - 8;
|
||||
|
||||
gdi.addRectangle(rc, color);
|
||||
drawBox(yp, cx, color);
|
||||
cx += xw;
|
||||
if (k % 6 == 5) {
|
||||
cx = xp;
|
||||
if ((k + 1) % maxTimesPerLine == 0) {
|
||||
cx = xp + mg4;
|
||||
yp += lh * 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gdi.dropLine(3);
|
||||
gdi.popX();
|
||||
rc.bottom = gdi.getCY();
|
||||
}
|
||||
|
||||
|
||||
void TabRunner::showVacancyList(gdioutput &gdi, const string &method, int classId)
|
||||
{
|
||||
gdi.clearPage(true);
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include "tabbase.h"
|
||||
#include "Printer.h"
|
||||
#include "autocompletehandler.h"
|
||||
#include <deque>
|
||||
|
||||
class Table;
|
||||
struct AutoCompleteRecord;
|
||||
@ -43,6 +44,15 @@ private:
|
||||
|
||||
void selectRunner(gdioutput &gdi, pRunner r);
|
||||
|
||||
int numReportRow = 1;
|
||||
int numReportColumn = 1;
|
||||
bool hideReportControls = false;
|
||||
bool showReportHeader = true;
|
||||
void addToReport(int cardNo, bool punchForShowReport);
|
||||
void addToReport(int id);
|
||||
|
||||
string computeKeyForReport();
|
||||
|
||||
wstring lastSearchExpr;
|
||||
unordered_set<int> lastFilter;
|
||||
DWORD timeToFill;
|
||||
@ -64,7 +74,7 @@ private:
|
||||
int runnerId;
|
||||
bool ownWindow;
|
||||
bool listenToPunches;
|
||||
vector< pair<int, bool> > runnersToReport;
|
||||
deque<pair<int, bool>> runnersToReport;
|
||||
|
||||
vector<pRunner> unknown_dns;
|
||||
vector<pRunner> known_dns;
|
||||
@ -76,7 +86,19 @@ private:
|
||||
PrinterObject splitPrinter;
|
||||
|
||||
void showRunnerReport(gdioutput &gdi);
|
||||
static void runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compactReport);
|
||||
|
||||
static void runnerReport(oEvent &oe, gdioutput &gdi,
|
||||
int id, bool compactReport,
|
||||
int maxWidth,
|
||||
RECT& rc);
|
||||
|
||||
static void teamReport(oEvent& oe, gdioutput& gdi,
|
||||
const oTeam *team,
|
||||
bool onlySelectedRunner,
|
||||
const deque<pair<int, bool>> &runners,
|
||||
int maxWidth,
|
||||
RECT &rc);
|
||||
|
||||
|
||||
void showVacancyList(gdioutput &gdi, const string &method="", int classId=0);
|
||||
void showCardsList(gdioutput &gdi);
|
||||
@ -126,7 +148,11 @@ public:
|
||||
bool loadPage(gdioutput &gdi);
|
||||
bool loadPage(gdioutput &gdi, int runnerId);
|
||||
|
||||
static void generateRunnerReport(oEvent &oe, gdioutput &gdi, vector<pair<int, bool>> &runnersToReport);
|
||||
static void generateRunnerReport(oEvent &oe,
|
||||
gdioutput &gdi,
|
||||
int numX, int numY,
|
||||
bool onlySelectedRunner,
|
||||
const deque<pair<int, bool>> &runnersToReport);
|
||||
|
||||
TabRunner(oEvent *oe);
|
||||
~TabRunner(void);
|
||||
|
||||
332
code/TabSI.cpp
332
code/TabSI.cpp
@ -84,7 +84,6 @@ TabSI::TabSI(oEvent* poe) :TabBase(poe), activeSIC(ConvertedTimeStatus::Unknown)
|
||||
minRunnerId = 0;
|
||||
inputId = 0;
|
||||
printErrorShown = false;
|
||||
NC = 8;
|
||||
splitPrinter.onlyChanged = false;
|
||||
}
|
||||
|
||||
@ -145,8 +144,7 @@ string TabSI::typeFromSndType(SND s) {
|
||||
return "";
|
||||
}
|
||||
|
||||
int TabSI::siCB(gdioutput& gdi, int type, void* data)
|
||||
{
|
||||
int TabSI::siCB(gdioutput& gdi, int type, void* data) {
|
||||
if (type == GUI_BUTTON) {
|
||||
ButtonInfo bi = *(ButtonInfo*)data;
|
||||
|
||||
@ -351,6 +349,12 @@ int TabSI::siCB(gdioutput& gdi, int type, void* data)
|
||||
ListBoxInfo lbi;
|
||||
if (gdi.getSelectedItem("ComPort", lbi)) {
|
||||
|
||||
if (lbi.data == 9999) {
|
||||
showTestingPanel = !showTestingPanel;
|
||||
loadPage(gdi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
swprintf_s(bf, 64, L"COM%d", lbi.getDataInt());
|
||||
wstring port = bf;
|
||||
|
||||
@ -705,11 +709,20 @@ int TabSI::siCB(gdioutput& gdi, int type, void* data)
|
||||
sic.CardNumber = gdi.getTextNo("SI");
|
||||
int f = convertAbsoluteTimeHMS(gdi.getText("Finish"), oe->getZeroTimeNum());
|
||||
int s = convertAbsoluteTimeHMS(gdi.getText("Start"), oe->getZeroTimeNum());
|
||||
int c = convertAbsoluteTimeHMS(gdi.getText("Check"), oe->getZeroTimeNum());
|
||||
|
||||
testStartTime.clear();
|
||||
testFinishTime.clear();
|
||||
testCheckTime.clear();
|
||||
testCardNumber = 0;
|
||||
|
||||
if (f < s) {
|
||||
f += 24 * timeConstHour;
|
||||
}
|
||||
sic.FinishPunch.Time = f % (24 * timeConstHour);
|
||||
sic.StartPunch.Time = s % (24 * timeConstHour);
|
||||
sic.CheckPunch.Time = c % (24 * timeConstHour);
|
||||
|
||||
if (!gdi.isChecked("HasFinish")) {
|
||||
sic.FinishPunch.Code = -1;
|
||||
sic.FinishPunch.Time = 0;
|
||||
@ -720,9 +733,20 @@ int TabSI::siCB(gdioutput& gdi, int type, void* data)
|
||||
sic.StartPunch.Time = 0;
|
||||
}
|
||||
|
||||
if (!gdi.isChecked("HasCheck")) {
|
||||
sic.CheckPunch.Code = -1;
|
||||
sic.CheckPunch.Time = 0;
|
||||
}
|
||||
|
||||
if (NC > testControls.size())
|
||||
testControls.resize(NC);
|
||||
|
||||
for (int i = 0; i < NC; i++)
|
||||
testControls[i] = gdi.getTextNo("C" + itos(i + 1));
|
||||
|
||||
double t = 0.1;
|
||||
for (sic.nPunch = 0; sic.nPunch<unsigned(NC); sic.nPunch++) {
|
||||
int c = gdi.getTextNo("C" + itos(sic.nPunch + 1));
|
||||
int c = testControls[sic.nPunch];
|
||||
sic.Punch[sic.nPunch].Time = ((int(f * t + s * (1.0 - t))/ timeUnitsPerSecond) % (24 * timeConstSecPerHour)) * timeUnitsPerSecond;
|
||||
t += ((1.0 - t) * (sic.nPunch + 1) / 10.0) * ((rand() % 100) + 400.0) / 500.0;
|
||||
if ((sic.nPunch % 11) == 1 || 5 == (sic.nPunch % 8))
|
||||
@ -754,31 +778,34 @@ int TabSI::siCB(gdioutput& gdi, int type, void* data)
|
||||
sic.FinishPunch.Code = -1;
|
||||
sic.CheckPunch.Code = -1;
|
||||
sic.StartPunch.Code = -1;
|
||||
|
||||
sic.CardNumber = gdi.getTextNo("SI");
|
||||
int f = convertAbsoluteTimeHMS(gdi.getText("Finish"), oe->getZeroTimeNum());
|
||||
if (f > 0) {
|
||||
sic.FinishPunch.Time = f;
|
||||
sic.FinishPunch.Code = 1;
|
||||
int t = convertAbsoluteTimeHMS(gdi.getText("PunchTime"), oe->getZeroTimeNum());
|
||||
testPunchTime.clear();
|
||||
testCardNumber = 0;
|
||||
|
||||
if (t > 0) {
|
||||
if (testType == oPunch::PunchStart) {
|
||||
sic.StartPunch.Time = t;
|
||||
sic.StartPunch.Code = 1;
|
||||
}
|
||||
else if (testType == oPunch::PunchFinish) {
|
||||
sic.FinishPunch.Time = t;
|
||||
sic.FinishPunch.Code = 1;
|
||||
}
|
||||
else if (testType == oPunch::PunchCheck) {
|
||||
sic.CheckPunch.Time = t;
|
||||
sic.CheckPunch.Code = 1;
|
||||
}
|
||||
else {
|
||||
sic.Punch[sic.nPunch].Code = gdi.getTextNo("ControlNumber");
|
||||
sic.Punch[sic.nPunch].Time = t;
|
||||
sic.nPunch = 1;
|
||||
}
|
||||
sic.punchOnly = true;
|
||||
sic.convertedTime = ConvertedTimeStatus::Hour24;
|
||||
gSI->addCard(sic);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int s = convertAbsoluteTimeHMS(gdi.getText("Start"), oe->getZeroTimeNum());
|
||||
if (s > 0) {
|
||||
sic.StartPunch.Time = s;
|
||||
sic.StartPunch.Code = 1;
|
||||
sic.punchOnly = true;
|
||||
gSI->addCard(sic);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sic.Punch[sic.nPunch].Code = gdi.getTextNo("C1");
|
||||
sic.Punch[sic.nPunch].Time = convertAbsoluteTimeHMS(gdi.getText("C2"), oe->getZeroTimeNum());
|
||||
sic.nPunch = 1;
|
||||
sic.punchOnly = true;
|
||||
gSI->addCard(sic);
|
||||
}
|
||||
else if (bi.id == "Cancel") {
|
||||
int origin = bi.getExtraInt();
|
||||
@ -1411,14 +1438,20 @@ int TabSI::siCB(gdioutput& gdi, int type, void* data)
|
||||
updateEntryInfo(gdi);
|
||||
}
|
||||
else if (bi.id == "ComPort") {
|
||||
wchar_t bf[64];
|
||||
bool active = true;
|
||||
if (bi.data == 9999)
|
||||
active = showTestingPanel;
|
||||
else {
|
||||
wchar_t bf[64];
|
||||
if (bi.text.substr(0, 3) != L"TCP")
|
||||
swprintf_s(bf, 64, L"COM%d", bi.getDataInt());
|
||||
else
|
||||
wcscpy_s(bf, L"TCP");
|
||||
|
||||
if (bi.text.substr(0, 3) != L"TCP")
|
||||
swprintf_s(bf, 64, L"COM%d", bi.getDataInt());
|
||||
else
|
||||
wcscpy_s(bf, L"TCP");
|
||||
active = gSI->isPortOpen(bf);
|
||||
}
|
||||
|
||||
if (gSI->isPortOpen(bf))
|
||||
if (active)
|
||||
gdi.setText("StartSI", lang.tl("Koppla ifrån"));
|
||||
else
|
||||
gdi.setText("StartSI", lang.tl("Aktivera"));
|
||||
@ -1463,9 +1496,15 @@ int TabSI::siCB(gdioutput& gdi, int type, void* data)
|
||||
updateEntryInfo(gdi);
|
||||
}
|
||||
else if (bi.id == "NC") {
|
||||
readTestData(gdi);
|
||||
NC = bi.data;
|
||||
PostMessage(gdi.getHWNDTarget(), WM_USER + 2, TSITab, 0);
|
||||
}
|
||||
else if (bi.id == "TestType") {
|
||||
readTestData(gdi);
|
||||
testType = bi.data;
|
||||
PostMessage(gdi.getHWNDTarget(), WM_USER + 2, TSITab, 0);
|
||||
}
|
||||
}
|
||||
else if (type == GUI_LINK) {
|
||||
TextInfo ti = *(TextInfo*)data;
|
||||
@ -1483,6 +1522,13 @@ int TabSI::siCB(gdioutput& gdi, int type, void* data)
|
||||
runnerMatchedId = r->getId();
|
||||
}
|
||||
}
|
||||
else if (ti.id == "edit") {
|
||||
int rId = ti.getExtraInt();
|
||||
if (oe->getRunner(rId, 0)) {
|
||||
TabRunner& tr = dynamic_cast<TabRunner&>(*gdi.getTabs().get(TRunnerTab));
|
||||
tr.loadPage(gdi, rId);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == GUI_COMBO) {
|
||||
ListBoxInfo bi = *(ListBoxInfo*)data;
|
||||
@ -1672,16 +1718,25 @@ int TabSI::siCB(gdioutput& gdi, int type, void* data)
|
||||
}
|
||||
else if (ii.id == "SI") {
|
||||
pRunner r = oe->getRunnerByCardNo(_wtoi(ii.text.c_str()), 0, oEvent::CardLookupProperty::ForReadout);
|
||||
if (r && r->getStartTime() > 0) {
|
||||
gdi.setText("Start", r->getStartTimeS());
|
||||
gdi.check("HasStart", false);
|
||||
int f = r->getStartTime() + (2800 + rand() % 1200) * timeConstSecond;
|
||||
gdi.setText("Finish", oe->getAbsTime(f));
|
||||
if (testType == 0 && r) {
|
||||
if (r->getStartTime() > 0) {
|
||||
gdi.setText("Start", r->getStartTimeS());
|
||||
gdi.check("HasStart", false);
|
||||
int f = r->getStartTime() + (2800 + rand() % 1200) * timeConstSecond;
|
||||
gdi.setText("Finish", oe->getAbsTime(f));
|
||||
int c = r->getStartTime() - (120 + rand() % 30) * timeConstSecond;
|
||||
gdi.setText("Check", oe->getAbsTime(c));
|
||||
}
|
||||
|
||||
pCourse pc = r->getCourse(false);
|
||||
if (pc) {
|
||||
if (testControls.size() < pc->getNumControls())
|
||||
testControls.resize(pc->getNumControls());
|
||||
for (int n = 0; n < pc->getNumControls(); n++) {
|
||||
if (pc->getControl(n) && n < NC) {
|
||||
gdi.setText("C" + itos(n + 1), pc->getControl(n)->getFirstNumber());
|
||||
if (pc->getControl(n)) {
|
||||
testControls[n] = pc->getControl(n)->getFirstNumber();
|
||||
if (n < NC)
|
||||
gdi.setText("C" + itos(n + 1), testControls[n]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1833,7 +1888,11 @@ void TabSI::refillComPorts(gdioutput& gdi)
|
||||
gdi.addItem("ComPort", L"TCP [OK]", active);
|
||||
}
|
||||
else
|
||||
gdi.addItem("ComPort", L"TCP");
|
||||
gdi.addItem("ComPort", L"TCP", 0);
|
||||
|
||||
gdi.addItem("ComPort", lang.tl("Testning"), 9999);
|
||||
if (showTestingPanel)
|
||||
active = 9999;
|
||||
|
||||
if (addTestPort)
|
||||
gdi.addItem("ComPort", L"TEST");
|
||||
@ -1909,7 +1968,7 @@ void TabSI::showReadCards(gdioutput& gdi, vector<SICard>& cards)
|
||||
if (r != 0)
|
||||
gdi.addStringUT(yp, xp + off[1], 0, r->getName(), off[2] - off[1] + margin);
|
||||
|
||||
gdi.addStringUT(yp, xp + off[2], 0, oe->getAbsTime(cards[k].FinishPunch.Time));
|
||||
gdi.addStringUT(yp, xp + off[2], 0, formatTimeHMS(cards[k].FinishPunch.Time));
|
||||
yp += gdi.getLineHeight();
|
||||
}
|
||||
}
|
||||
@ -1941,59 +2000,122 @@ bool TabSI::loadPage(gdioutput& gdi) {
|
||||
|
||||
firstLoadedAfterNew = false;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
gdi.fillRight();
|
||||
gdi.pushX();
|
||||
gdi.addInput("SI", L"", 10, SportIdentCB, L"SI");
|
||||
int s = timeConstHour + (rand() % 60) * timeConstMinute;
|
||||
int f = s + timeConstHour / 2 + ((rand() % 3600) / 3) * timeConstSecond;
|
||||
|
||||
gdi.setCX(gdi.getCX() + gdi.getLineHeight());
|
||||
if (showTestingPanel) {
|
||||
RECT rc;
|
||||
rc.left = gdi.getCX();
|
||||
rc.top = gdi.getCY();
|
||||
|
||||
gdi.dropLine(1.4);
|
||||
gdi.addCheckbox("HasStart", "");
|
||||
gdi.dropLine(-1.4);
|
||||
gdi.setCX(gdi.getCX() - gdi.getLineHeight());
|
||||
gdi.addInput("Start", oe->getAbsTime(s), 6, 0, L"Start");
|
||||
gdi.setCX(gdi.getCX() + gdi.scaleLength(4));
|
||||
gdi.setCY(gdi.getCY() + gdi.scaleLength(4));
|
||||
|
||||
gdi.dropLine(1.4);
|
||||
gdi.addCheckbox("HasFinish", "");
|
||||
gdi.dropLine(-1.4);
|
||||
gdi.setCX(gdi.getCX() - gdi.getLineHeight());
|
||||
gdi.addString("", fontMediumPlus, "Inmatning Testning");
|
||||
|
||||
gdi.addInput("Finish", oe->getAbsTime(f), 6, 0, L"Mål");
|
||||
gdi.addSelection("NC", 45, 200, SportIdentCB, L"NC");
|
||||
const int src[11] = { 33, 34, 45, 50, 36, 38, 59, 61, 62, 67, 100 };
|
||||
gdi.fillRight();
|
||||
gdi.pushX();
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
gdi.addItem("NC", itow(i), i);
|
||||
gdi.addSelection("TestType", 100, 100, SportIdentCB, L"Typ:");
|
||||
gdi.addItem("TestType", lang.tl("Avläsning"), 0);
|
||||
gdi.addItem("TestType", lang.tl("Mål"), 2);
|
||||
gdi.addItem("TestType", lang.tl("Start"), 1);
|
||||
gdi.addItem("TestType", lang.tl("Check"), 3);
|
||||
gdi.addItem("TestType", lang.tl("Radio"), 10);
|
||||
|
||||
gdi.selectItemByData("NC", NC);
|
||||
gdi.selectItemByData("TestType", testType);
|
||||
|
||||
gdi.addInput("SI", testCardNumber > 0 ? itow(testCardNumber) : L"", 10, SportIdentCB, L"Bricknummer:");
|
||||
|
||||
if (testType == 0) {
|
||||
int s = timeConstHour + (rand() % 60) * timeConstMinute;
|
||||
int f = s + timeConstHour / 2 + ((rand() % 3600) / 3) * timeConstSecond;
|
||||
wstring ss = oe->getAbsTime(s);
|
||||
wstring fs = oe->getAbsTime(f);
|
||||
wstring cs = oe->getAbsTime(s - (60 + rand() % 60) * timeConstSecond);
|
||||
|
||||
if (!testStartTime.empty())
|
||||
ss = testStartTime;
|
||||
if (!testFinishTime.empty())
|
||||
fs = testFinishTime;
|
||||
if (!testCheckTime.empty())
|
||||
cs = testCheckTime;
|
||||
|
||||
gdi.setCX(gdi.getCX() + gdi.getLineHeight());
|
||||
|
||||
gdi.dropLine(1.6);
|
||||
gdi.addCheckbox("HasCheck", "", nullptr, useTestCheck);
|
||||
gdi.dropLine(-1.6);
|
||||
gdi.setCX(gdi.getCX() - gdi.getLineHeight());
|
||||
gdi.addInput("Check", cs, 6, 0, L"Check:");
|
||||
|
||||
gdi.dropLine(1.6);
|
||||
gdi.addCheckbox("HasStart", "", nullptr, useTestStart);
|
||||
gdi.dropLine(-1.6);
|
||||
gdi.setCX(gdi.getCX() - gdi.getLineHeight());
|
||||
gdi.addInput("Start", ss, 6, 0, L"Start:");
|
||||
|
||||
gdi.dropLine(1.6);
|
||||
gdi.addCheckbox("HasFinish", "", nullptr, useTestFinish);
|
||||
gdi.dropLine(-1.6);
|
||||
gdi.setCX(gdi.getCX() - gdi.getLineHeight());
|
||||
|
||||
gdi.addInput("Finish", fs, 6, 0, L"Mål:");
|
||||
gdi.addSelection("NC", 45, 200, SportIdentCB, L"Stämplingar:");
|
||||
const int src[11] = { 33, 34, 45, 50, 36, 38, 59, 61, 62, 67, 100 };
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
gdi.addItem("NC", itow(i), i);
|
||||
|
||||
gdi.selectItemByData("NC", NC);
|
||||
|
||||
for (int i = 0; i < NC; i++) {
|
||||
int level = min(i, NC - i) / 5;
|
||||
int c;
|
||||
if (i < NC / 2) {
|
||||
int ix = i % 6;
|
||||
c = src[ix] + level * 10;
|
||||
if (c == 100)
|
||||
c = 183;
|
||||
}
|
||||
else {
|
||||
int ix = 10 - (NC - i - 1) % 5;
|
||||
c = src[ix] + level * 10;
|
||||
}
|
||||
|
||||
if (i < testControls.size())
|
||||
c = testControls[i];
|
||||
|
||||
gdi.addInput("C" + itos(i + 1), itow(c), 3, 0, L"#C" + itow(i + 1));
|
||||
}
|
||||
|
||||
gdi.dropLine();
|
||||
gdi.fillDown();
|
||||
gdi.addButton("Save", "Spara", SportIdentCB);
|
||||
gdi.popX();
|
||||
|
||||
for (int i = 0; i < NC; i++) {
|
||||
int level = min(i, NC - i) / 5;
|
||||
int c;
|
||||
if (i < NC / 2) {
|
||||
int ix = i % 6;
|
||||
c = src[ix] + level * 10;
|
||||
if (c == 100)
|
||||
c = 183;
|
||||
}
|
||||
else {
|
||||
int ix = 10 - (NC - i - 1) % 5;
|
||||
c = src[ix] + level * 10;
|
||||
}
|
||||
int p = timeConstHour + (rand() % 60) * timeConstMinute;
|
||||
wstring ps = oe->getAbsTime(p);
|
||||
|
||||
if (!testPunchTime.empty())
|
||||
ps = testPunchTime;
|
||||
|
||||
if (testType == 10)
|
||||
gdi.addInput("ControlNumber", itow(testRadioNumber), 6, 0, L"Kontroll:");
|
||||
|
||||
gdi.addInput("C" + itos(i + 1), itow(c), 3, 0, L"#C" + itow(i + 1));
|
||||
gdi.addInput("PunchTime", ps, 6, 0, L"Tid:");
|
||||
|
||||
gdi.dropLine();
|
||||
gdi.fillDown();
|
||||
gdi.addButton("SaveP", "Spara", SportIdentCB);
|
||||
gdi.popX();
|
||||
}
|
||||
rc.right = gdi.getWidth();
|
||||
rc.bottom = gdi.getCY();
|
||||
gdi.addRectangle(rc, GDICOLOR::colorLightMagenta);
|
||||
gdi.dropLine();
|
||||
}
|
||||
|
||||
gdi.dropLine();
|
||||
gdi.addButton("Save", "Bricka", SportIdentCB);
|
||||
gdi.fillDown();
|
||||
|
||||
gdi.addButton("SaveP", "Stämpling", SportIdentCB);
|
||||
gdi.popX();
|
||||
#endif
|
||||
gdi.addString("", boldLarge, "SportIdent");
|
||||
gdi.dropLine();
|
||||
|
||||
@ -2944,6 +3066,7 @@ bool TabSI::processCard(gdioutput& gdi, pRunner runner, const SICard& csic, bool
|
||||
runner->setStatus(StatusOK, true, oBase::ChangeType::Update, false);
|
||||
SICard sic(csic);
|
||||
StoredReadout rout;
|
||||
rout.runnerId = runner->getId();
|
||||
|
||||
if (!csic.isManualInput()) {
|
||||
pCard card = gEvent->allocateCard(runner);
|
||||
@ -3045,7 +3168,7 @@ bool TabSI::processCard(gdioutput& gdi, pRunner runner, const SICard& csic, bool
|
||||
rout.statusline += lang.tl(L", Prel. bomtid: ") + runner->getMissedTimeS();
|
||||
|
||||
rout.rentCard = runner->isHiredCard() || oe->isHiredCard(sic.CardNumber);
|
||||
|
||||
|
||||
if (!silent) {
|
||||
rout.render(gdi, rout.computeRC(gdi));
|
||||
gdi.scrollToBottom();
|
||||
@ -3125,6 +3248,12 @@ RECT TabSI::StoredReadout::computeRC(gdioutput& gdi) const {
|
||||
void TabSI::StoredReadout::render(gdioutput& gdi, const RECT& rc) const {
|
||||
gdi.fillDown();
|
||||
gdi.addRectangle(rc, color, true);
|
||||
|
||||
//gdi.addString("edit", rc.right - gdi.scaleLength(30), rc.top+gdi.scaleLength(4), textImage, "S" + itos(gdi.scaleLength(24)));
|
||||
if (runnerId > 0) {
|
||||
gdi.addImage("edit", rc.top + gdi.scaleLength(4), rc.right - gdi.scaleLength(30), 0,
|
||||
itow(IDI_MEOSEDIT), gdi.scaleLength(24), gdi.scaleLength(24), SportIdentCB).setExtra(runnerId);
|
||||
}
|
||||
int lh = gdi.getLineHeight();
|
||||
int marg = gdi.scaleLength(20);
|
||||
int tmarg = gdi.scaleLength(6);
|
||||
@ -3215,6 +3344,8 @@ wstring TabSI::getTimeAfterString(const oRunner* runner) {
|
||||
|
||||
void TabSI::processPunchOnly(gdioutput& gdi, const SICard& csic)
|
||||
{
|
||||
gdi.makeEvent("PunchCard", "sireadout", csic.CardNumber, 0, true);
|
||||
|
||||
SICard sic = csic;
|
||||
DWORD loaded;
|
||||
gEvent->convertTimes(nullptr, sic);
|
||||
@ -3707,19 +3838,10 @@ void TabSI::tieCard(gdioutput& gdi) {
|
||||
}
|
||||
|
||||
void TabSI::showAssignCard(gdioutput& gdi, bool showHelp) {
|
||||
//gdi.fillDown();
|
||||
//gdi.setRestorePoint("AssignCardBase");
|
||||
if (interactiveReadout) {
|
||||
if (showHelp) {
|
||||
checkBoxToolBar(gdi, { CheckBox::Interactive, CheckBox::AutoTie, CheckBox::AutoTieRent });
|
||||
gdi.addString("", 10, L"Avmarkera 'X' för att hantera alla bricktildelningar samtidigt.#" + lang.tl("Interaktiv inläsning"));
|
||||
/*gdi.dropLine(0.5);
|
||||
gdi.addCheckbox("AutoTie", "Knyt automatiskt efter inläsning", SportIdentCB, oe->getPropertyInt("AutoTie", 1) != 0);
|
||||
gdi.addCheckbox("AutoTieRent", "Automatisk hyrbrickshantering genom registrerade hyrbrickor", SportIdentCB, oe->getPropertyInt("AutoTieRent", 1) != 0);
|
||||
if (!oe->hasHiredCardData()) {
|
||||
gdi.disableInput("AutoTieRent");
|
||||
gdi.check("AutoTieRent", false);
|
||||
}*/
|
||||
gdi.dropLine(0.5);
|
||||
gdi.setRestorePoint("ManualTie");
|
||||
}
|
||||
@ -3730,8 +3852,7 @@ void TabSI::showAssignCard(gdioutput& gdi, bool showHelp) {
|
||||
gdi.addString("", 10, L"Markera 'X' för att hantera deltagarna en och en.#" + lang.tl("Interaktiv inläsning"));
|
||||
}
|
||||
|
||||
gEvent->assignCardInteractive(gdi, SportIdentCB);
|
||||
gdi.refresh();
|
||||
gEvent->assignCardInteractive(gdi, SportIdentCB, sortAssignCards);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -4291,6 +4412,8 @@ void TabSI::clearCompetitionData() {
|
||||
|
||||
logger.reset();
|
||||
numSavedCardsOnCmpOpen = savedCards.size();
|
||||
|
||||
sortAssignCards = SortOrder::Custom;
|
||||
}
|
||||
|
||||
SICard& TabSI::getCard(int id) const {
|
||||
@ -5088,7 +5211,7 @@ void TabSI::showReadoutStatus(gdioutput& gdi, const oRunner* r,
|
||||
|
||||
if (rentalCard) {
|
||||
gdi.addRectangle(rc, colorYellow);
|
||||
gdi.addStringUT(rc.top + (rc.bottom - rc.top) / 3, mrg, boldHuge | textCenter,
|
||||
gdi.addString("", rc.top + (rc.bottom - rc.top) / 3, mrg, boldHuge | textCenter,
|
||||
"Vänligen återlämna hyrbrickan.", w - 3 * mrg);
|
||||
}
|
||||
|
||||
@ -5168,3 +5291,26 @@ void TabSI::fillMappings(gdioutput& gdi) const {
|
||||
gdi.addItem("Mappings", itow(mp.first) + L" \u21A6 " + oPunch::getType(mp.second), mp.first);
|
||||
}
|
||||
}
|
||||
|
||||
void TabSI::readTestData(gdioutput& gdi) {
|
||||
testCardNumber = gdi.getTextNo("SI");
|
||||
if (gdi.hasWidget("PunchTime")) {
|
||||
testPunchTime = gdi.getText("PunchTime");
|
||||
}
|
||||
else {
|
||||
useTestCheck = gdi.isChecked("HasCheck");
|
||||
useTestStart = gdi.isChecked("HasStart");
|
||||
useTestFinish = gdi.isChecked("HasFinish");
|
||||
|
||||
testStartTime = gdi.getText("Start");
|
||||
testFinishTime = gdi.getText("Finish");
|
||||
testCheckTime = gdi.getText("Check");
|
||||
|
||||
if (NC > testControls.size())
|
||||
testControls.resize(NC);
|
||||
|
||||
for (int i = 0; i < NC; i++)
|
||||
testControls[i] = gdi.getTextNo("C" + itos(i+1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
26
code/TabSI.h
26
code/TabSI.h
@ -94,6 +94,8 @@ private:
|
||||
shared_ptr<GuiHandler> resetHiredCardHandler;
|
||||
GuiHandler *getResetHiredCardHandler();
|
||||
|
||||
SortOrder sortAssignCards = SortOrder::Custom;
|
||||
|
||||
int runnerMatchedId;
|
||||
bool printErrorShown;
|
||||
void printProtected(gdioutput &gdi, gdioutput &gdiprint);
|
||||
@ -185,17 +187,32 @@ private:
|
||||
|
||||
static int analyzePunch(SIPunch &p, int &start, int &accTime, int &days);
|
||||
|
||||
|
||||
void createCompetitionFromCards(gdioutput &gdi);
|
||||
|
||||
int NC;
|
||||
int NC = 8;
|
||||
int testType = 0;
|
||||
bool showTestingPanel = false;
|
||||
wstring testStartTime;
|
||||
bool useTestStart = true;
|
||||
wstring testFinishTime;
|
||||
bool useTestFinish = true;
|
||||
wstring testCheckTime;
|
||||
bool useTestCheck = false;
|
||||
int testRadioNumber = 50;
|
||||
wstring testPunchTime;
|
||||
vector<int> testControls;
|
||||
int testCardNumber = 0;
|
||||
|
||||
void readTestData(gdioutput& gdi);
|
||||
|
||||
|
||||
class EditCardData : public GuiHandler {
|
||||
TabSI *tabSI;
|
||||
EditCardData(const EditCardData&);
|
||||
EditCardData &operator=(const EditCardData&);
|
||||
public:
|
||||
EditCardData() : tabSI(0) {}
|
||||
EditCardData(const EditCardData&) = delete;
|
||||
EditCardData& operator=(const EditCardData&) = delete;
|
||||
|
||||
void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type);
|
||||
friend class TabSI;
|
||||
};
|
||||
@ -252,6 +269,7 @@ private:
|
||||
vector<int> MP;
|
||||
GDICOLOR color;
|
||||
bool rentCard = false;
|
||||
int runnerId = 0;
|
||||
|
||||
RECT computeRC(gdioutput &gdi) const;
|
||||
void render(gdioutput &gdi, const RECT &rc) const;
|
||||
|
||||
@ -241,11 +241,11 @@ int TabSpeaker::processButton(gdioutput &gdi, const ButtonInfo &bu)
|
||||
gdi.dropLine(3);
|
||||
gdi.popX();
|
||||
gdi.registerEvent("DataUpdate", tabSpeakerCB);
|
||||
vector<pair<int, bool>> runnersToReport;
|
||||
deque<pair<int, bool>> runnersToReport;
|
||||
if (runnerId > 0) {
|
||||
runnersToReport.emplace_back(runnerId, false);
|
||||
}
|
||||
TabRunner::generateRunnerReport(*oe, gdi, runnersToReport);
|
||||
TabRunner::generateRunnerReport(*oe, gdi, 1, 1, false, runnersToReport);
|
||||
gdi.refresh();
|
||||
}
|
||||
else if (bu.id == "Priority") {
|
||||
|
||||
@ -274,7 +274,7 @@ void Table::filter(int col, const wstring &filt, bool forceFilter)
|
||||
|
||||
wchar_t filt_lc[1024];
|
||||
wcscpy_s(filt_lc, filt.c_str());
|
||||
CharLowerBuff(filt_lc, filt.length());
|
||||
prepareMatchString(filt_lc, filt.length());
|
||||
|
||||
sortIndex.resize(2);
|
||||
for (size_t k=2;k<baseIndex.size();k++) {
|
||||
|
||||
BIN
code/edit.png
Normal file
BIN
code/edit.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 677 B |
@ -256,7 +256,7 @@ Checkenhet = Check unit
|
||||
Choose result module = Choose result module
|
||||
ClassAvailableMaps = Available maps for class
|
||||
ClassCourseResult = Class, course, result
|
||||
ClassDefaultResult = Class, Default result
|
||||
ClassDefaultResult = Class, default result
|
||||
ClassFinishTime = Class, finish time
|
||||
ClassKnockoutTotalResult = Class, knock-out total result
|
||||
ClassLength = Course length for class
|
||||
@ -2674,3 +2674,8 @@ Bevara höjd/bredd-relationen = Preserve aspect ratio
|
||||
RunnerLegTeamLeaderName = First competitor in team to finish leg
|
||||
info:offsetclassid = If you import entries and classes from different sources to the same competition, it might happen that there are clashes in the Id numbers of the classes. To separate the classes, you may enter an offset for the Class Id when working with files from a particular source; this will be added to the Id numbers.\n\nYou must specify the same offset each time you import from that source.\n\n A suitble number could be1000 (which will work as long as every Id is less that 1000).
|
||||
Förskjutning av klassers Id = Offset Class ID
|
||||
Tilldela nummerlapp till vakanter = Assign bibs to vacancies
|
||||
Avläsning = Readout
|
||||
Inmatning Testning = Input Testing
|
||||
Testning = Testing
|
||||
CourseNumControls = Number of controls
|
||||
|
||||
@ -214,7 +214,9 @@ Bevakar händelser i X = Moniteur d'évènement X
|
||||
Bevakningsprioritering = Sélectionner le coureur à surveiller
|
||||
Bevara höjd/bredd-relationen = Conserver les proportions
|
||||
Bibs = Dossards
|
||||
Bild = Image
|
||||
Bild under text = Mettre l'image sous le texte
|
||||
Bilder = Images
|
||||
Block = Bloc
|
||||
Blockbredd = Largeur de bloc
|
||||
Bläddra = Parcourir
|
||||
@ -265,7 +267,7 @@ ClassKnockoutTotalResult = Class, knock-out total result
|
||||
ClassLength = Longueur du circuit pour la catégorie
|
||||
ClassLiveResult = Live results (temps radios), par catégorie
|
||||
ClassName = Catégorie
|
||||
ClassNumEntries = Nombre d'inscrits
|
||||
ClassNumEntries = Nombre d'inscrits dans la catégorie
|
||||
ClassPoints = Catégorie, points
|
||||
ClassResult = Catégorie, résultat
|
||||
ClassResultFraction = Pourcentage de la catégorie ayant terminé
|
||||
@ -422,6 +424,7 @@ Elektronisk godkänd = Accepté électroniquement
|
||||
Elit = Élite
|
||||
Elitavgift = Frais élites
|
||||
Elitklasser = Catégorie élite
|
||||
Empty Results Split Print = Temps intermédiaires sans résultats
|
||||
En bana med slingor tillåter deltagaren att ta slingorna i valfri ordning = Un circuit avec des boucles autorise le coureur à effectuer les boucles dans n'importe quel ordre.
|
||||
En gafflad sträcka = Circuit avec variations
|
||||
En klass kan inte slås ihop med sig själv = Vous ne pouvez pas fusionner une catégorie avec elle-même
|
||||
@ -621,6 +624,7 @@ Förhindra att laget deltar i någon omstart = Permet à l'équipe de ne pas pre
|
||||
Förhindra omstart = Refuser le départ des attardés
|
||||
Förhöjd avgift = Frais supplémentaires
|
||||
Förskjutning = Déplacement
|
||||
Förskjutning av klassers Id = Décalage de l'identifiant de catégorie
|
||||
Först = En premier
|
||||
Först-i-mål, gemensam = Du premier au dernier, commun
|
||||
Först-i-mål, klassvis = Du premier au dernier, par catégorie
|
||||
@ -685,6 +689,7 @@ Hittar inte hjälpfilen, X = Documentation introuvable, X
|
||||
Hittar inte klass X = Impossible de trouver la catégorie X
|
||||
Hjälp = Aide
|
||||
Hoppar över stafettklass: X = Sauter la catégorie de relais: X
|
||||
Horisontell = Horizontal
|
||||
Horizontell = Horizontalement
|
||||
Huvudlista = Liste principale
|
||||
Hyravgift = Tarif de location
|
||||
@ -763,6 +768,8 @@ Inconsistent qualification rule, X = Règle de qualification incohérente, X
|
||||
Index = Index
|
||||
Index in X[index] = Index en X[index]
|
||||
Individual Example = Exemple de course individuelle
|
||||
Individual Results Split Print = Avec résultats individuels
|
||||
Individual Rogaining Split Print = Avec résultats de la course au score
|
||||
Individual result by finish time = Résultat individuel sur l'heure d'arrivée
|
||||
Individual results in a club = Résultats individuel au sein du club
|
||||
Individuell = par catégorie
|
||||
@ -1009,6 +1016,7 @@ Liveresultat, radiotider = Résultats en direct avec radios
|
||||
Ljud = Son
|
||||
Ljudfiler, baskatalog = Répertoire de base des fichiers sonores
|
||||
Ljudval = Sélection des sons
|
||||
Lokal kopia från X = Copie locale de X
|
||||
Lokalt = Localement
|
||||
Long = Longue
|
||||
Longitud = Longitude
|
||||
@ -1402,6 +1410,8 @@ Relation till föregående = Lien avec le précédent
|
||||
Relativ skalfaktor för typsnittets storlek i procent = Facteur d'échelle pour la police (pourcentage)
|
||||
Relay Example = Exemple de relais
|
||||
Relay Example (Lokal kopia från: localhost) = Exemple de relais (Copie locale depuis : localhost)
|
||||
Relay Results Split Print = Avec résultats du relais
|
||||
Relay/Team Results Split Print = Avec résultats du relais/de l'équipe
|
||||
Relays = Relais
|
||||
Rep = Arrêt attardés
|
||||
Reparera vald tävling = Réparer la compétition sélectionnée
|
||||
@ -1526,6 +1536,7 @@ RunnerId = Licence/ID
|
||||
RunnerLeg = Concurrent (variation spécifique)
|
||||
RunnerLegNumber = Numéro de relais groupé du coureur
|
||||
RunnerLegNumberAlpha = Numéro de relais exact du coureur
|
||||
RunnerLegTeamLeaderName = Premier membre de l'équipe à terminer son circuit
|
||||
RunnerName = Nom du coureur
|
||||
RunnerNationality = Nationalité du coureur
|
||||
RunnerPaid = Payé
|
||||
@ -1888,6 +1899,7 @@ Tabelläge = Mode table
|
||||
Tar bort X = Retrait de X
|
||||
Team = Équipe
|
||||
Team Rogaining = Course au score en équipe
|
||||
Team Rogaining Split Print = Avec résultats de la course au score en équipe
|
||||
TeamBib = Dossard de l'équipe
|
||||
TeamClub = Club de l'équipe
|
||||
TeamCourseName = Nom du circuit pour l'équipe/la branche
|
||||
@ -2217,6 +2229,7 @@ Välj alla klasser = Sélectionner toutes les catégories
|
||||
Välj allt = Sélectionner tout
|
||||
Välj automatiskt = Sélection automatique
|
||||
Välj bild = Choisir une image
|
||||
Välj bland befintliga bilder = Sélectionner une image existante
|
||||
Välj deltagare för förhandsgranskning = Sélectionner un coureur pour prévisualisation
|
||||
Välj den etapp som föregår denna tävling = Sélectionner l'étape précédente
|
||||
Välj den etapp som kommer efter denna tävling = Sélectionner l'étape suivante
|
||||
@ -2428,11 +2441,12 @@ info:mapcontrol = MeOS ne sait pas déterminer la fonction d'un boîtier s'il n'
|
||||
info:multieventnetwork = Pour prendre en charge plus d'une étape vous devez travailler localement. Faite une copie de sauvegarde de la compétition, ouvrez-la en local et transférez les résultats à l'étape suivante. Enfin, remontez l'étape suivante sur le serveur.
|
||||
info:multiple_start = Un coureur peut faire plusieurs fois le même circuit. Une nouvelle inscription est créée à chaque lecture de la puce
|
||||
info:nosplitprint = Chargement de la liste personnalisée impossible\n\nCelle par défaut la remplace
|
||||
info:offsetclassid = Si vous importez des inscrits et des catégories depuis des sources différentes dans la même compétition, il peut y avoir des conflits entre les numéros d'identifiant des catégories. Pour différencier les catégories, vous pouvez entrer un décalage de la valeur de l'identifiant des catégorires pour chacune des sources. Celui-ci sera ajouté à l'identifiant existant.\n\nVous pouvez par exemple entrer 1000 (si aucune catégorie n'a déjà un identifiant supérieur à 1000).
|
||||
info:pageswithcolumns = Montrer la liste page par page, avec un nombre spécifié de colonnes. Les infos sont mises à jour à chaque bouclage.
|
||||
info:readout_action = X: Puce no. Y lue.\nDes actions manuelles sont requises.
|
||||
info:readout_queue = X: Puce no. Y lue.\nLa puce a été mise en file d'attente.
|
||||
info:readoutbase = Activez le boîtier SI en sélectionnant son port COM ou en recherchant les boîtiers SI installés. Appuyez sur Information pour obtenir le statut du port sélectionné.\n\nLecture Interactive vous permet de gérer directement les problèmes tels qu'un numéro de puce erroné. N'utilisez pas cette possibilité quand les coureurs ayant des problèmes sont pris en charge séparément.\n\nLa base de données des coureurs est utilisée si vous voulez ajouter automatiquement de nouveaux coureurs. Les poinçons sont utilisés pour trouver (détecter) la bonne catégorie.
|
||||
info:readoutmore = Verrouillez la fonction pour éviter toute modification accidentelle.\n\nSélection des sons vous permet de lancer différents sons lors de la lecture des puces pour être plus facilement informé des problèmes.\n\n"Fenêtre de prévisualisation coureur" affiche une nouvelle fenêtre destinée au coureur qui lit sa puce, regroupant les informations principales de sa course.\n\nPlusieurs courses pour un coureur est utile si un coureur est autorisé a faire plusieurs fois son circuit. Une nouvelle inscriprion est créée à chaque lecture de la puce.
|
||||
info:readoutmore = Verrouillez la fonction pour éviter toute modification accidentelle.\n\nSélection des sons vous permet de lancer différents sons lors de la lecture des puces pour être plus facilement informé des problèmes.\n\n"Fenêtre de prévisualisation coureur" affiche une nouvelle fenêtre destinée au coureur qui lit sa puce, regroupant les informations principales de sa course.\n\nPlusieurs courses pour un coureur est utile si un coureur est autorisé a faire plusieurs fois son circuit. Une nouvelle inscription est créée à chaque lecture de la puce.
|
||||
info:readoutwindow = Cette fenêtre affiche les informations principales de chaque lecture de puce
|
||||
info:runnerdbonline = Comme vous êtes connecté à un serveur, il n'est pas possible d'éditer les bases de données club et coureurs manuellement. Effectuez les changements avant d'uploader la compétition sur un serveur. Il est également possible de remplacer la base de données existante sur le serveur en important une nouvelle base (à partir de IOF XML).
|
||||
info:teamcourseassignment = Le fichier des circuits IOF XML 3.0 contient les variations des équipes. Pour importer ces données, vous devez préparer la compétition en fonction des données du fichier :\n\n1.Assurez-vous que les catégories de relais ont le bon nombre de branches.\n2. Affectez les dossards à chaque catégorie. Passez par la Configuration Rapide dans l'onglet Catégories et renseignez le premier dossard de chaque catégorie (avec la répartition automatique des dossards). Vous pouvez aussi importer les équipes et leur attribuer des dossards comme d'habitude.\n\n\n3. Importez les circuits. Vous pouvez importer plusieurs fois ce fichier si nécessaire pour mettre à jour les variations.
|
||||
|
||||
@ -888,6 +888,7 @@ TextInfo& gdioutput::addImage(const string& id, int yp, int xp, int format,
|
||||
|
||||
imageReferences.push_back(&TI);
|
||||
|
||||
TI.id = id;
|
||||
TI.format = format | textImage;
|
||||
TI.xp = xp;
|
||||
TI.yp = yp;
|
||||
@ -1256,7 +1257,7 @@ ButtonInfo &gdioutput::addButton(int x, int y, int w, const string &id,
|
||||
updatePos(x, y, w+scaleLength(GDI_BUTTON_SPACING), height+5);
|
||||
|
||||
bi.xp=x;
|
||||
bi.yp=y;
|
||||
bi.yp = y - 1;
|
||||
bi.width = w;
|
||||
bi.text=ttext;
|
||||
bi.id=id;
|
||||
@ -1321,23 +1322,23 @@ ButtonInfo &gdioutput::addCheckbox(int x, int y, const string &id, const string
|
||||
return addCheckbox(x,y,id, widen(text), cb, Checked, widen(tooltip), AbsPos);
|
||||
}
|
||||
|
||||
ButtonInfo &gdioutput::addCheckbox(int x, int y, const string &id, const wstring &text,
|
||||
GUICALLBACK cb, bool Checked, const wstring &tooltip, bool AbsPos)
|
||||
ButtonInfo& gdioutput::addCheckbox(int x, int y, const string& id, const wstring& text,
|
||||
GUICALLBACK cb, bool Checked, const wstring& tooltip, bool AbsPos)
|
||||
{
|
||||
ButtonInfo bi;
|
||||
SIZE size;
|
||||
|
||||
wstring ttext = lang.tl(text);
|
||||
HDC hDC=GetDC(hWndTarget);
|
||||
HDC hDC = GetDC(hWndTarget);
|
||||
SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT));
|
||||
GetTextExtentPoint32(hDC, L"M", 1, &size);
|
||||
|
||||
int ox=OffsetX;
|
||||
int oy=OffsetY;
|
||||
int ox = OffsetX;
|
||||
int oy = OffsetY;
|
||||
|
||||
if (AbsPos) {
|
||||
ox=0;
|
||||
oy=0;
|
||||
ox = 0;
|
||||
oy = 0;
|
||||
}
|
||||
|
||||
int h = size.cy;
|
||||
@ -1345,15 +1346,16 @@ ButtonInfo &gdioutput::addCheckbox(int x, int y, const string &id, const wstring
|
||||
GetTextExtentPoint32(hDC, ttext.c_str(), ttext.length(), &size);
|
||||
ReleaseDC(hWndTarget, hDC);
|
||||
|
||||
bi.hWnd=CreateWindowEx(0,L"BUTTON", L"", WS_TABSTOP|WS_VISIBLE|
|
||||
WS_CHILD | WS_CLIPSIBLINGS |BS_AUTOCHECKBOX|BS_NOTIFY,
|
||||
x-ox, y-oy + (size.cy-h)/2, h, h, hWndTarget, NULL,
|
||||
(HINSTANCE)GetWindowLongPtr(hWndTarget, GWLP_HINSTANCE), NULL);
|
||||
int cbY = y + (size.cy - h) / 2;
|
||||
bi.hWnd = CreateWindowEx(0, L"BUTTON", L"", WS_TABSTOP | WS_VISIBLE |
|
||||
WS_CHILD | WS_CLIPSIBLINGS | BS_AUTOCHECKBOX | BS_NOTIFY,
|
||||
x - ox, cbY - oy, h, h, hWndTarget, NULL,
|
||||
(HINSTANCE)GetWindowLongPtr(hWndTarget, GWLP_HINSTANCE), NULL);
|
||||
|
||||
TextInfo &desc = addStringUT(y , x + (3*h)/2, 0, ttext, 0, checkBoxCallback);
|
||||
TextInfo& desc = addStringUT(y, x + (3 * h) / 2, 0, ttext, 0, checkBoxCallback);
|
||||
desc.id = "T" + id;
|
||||
|
||||
SendMessage(bi.hWnd, WM_SETFONT, (WPARAM) getGUIFont(), 0);
|
||||
SendMessage(bi.hWnd, WM_SETFONT, (WPARAM)getGUIFont(), 0);
|
||||
|
||||
if (Checked)
|
||||
SendMessage(bi.hWnd, BM_SETCHECK, BST_CHECKED, 0);
|
||||
@ -1366,18 +1368,18 @@ ButtonInfo &gdioutput::addCheckbox(int x, int y, const string &id, const wstring
|
||||
else
|
||||
updatePos(x, y, size.cx + int(30 * scale), desc.textRect.bottom - desc.textRect.top + scaleLength(4));
|
||||
}
|
||||
if (tooltip.length()>0) {
|
||||
if (tooltip.length() > 0) {
|
||||
addToolTip(id, tooltip, bi.hWnd);
|
||||
addToolTip(desc.id, tooltip, 0, &desc.textRect);
|
||||
}
|
||||
bi.isCheckbox = true;
|
||||
bi.xp=x;
|
||||
bi.yp=y;
|
||||
bi.width = desc.textRect.right - (x-ox);
|
||||
bi.text=ttext;
|
||||
bi.id=id;
|
||||
bi.callBack=cb;
|
||||
bi.AbsPos=AbsPos;
|
||||
bi.xp = x;
|
||||
bi.yp = cbY;
|
||||
bi.width = desc.textRect.right - (x - ox);
|
||||
bi.text = ttext;
|
||||
bi.id = id;
|
||||
bi.callBack = cb;
|
||||
bi.AbsPos = AbsPos;
|
||||
bi.originalState = Checked;
|
||||
bi.isEdit(true);
|
||||
BI.push_back(bi);
|
||||
@ -2240,7 +2242,7 @@ void gdioutput::processButtonMessage(ButtonInfo &bi, WPARAM wParam)
|
||||
if (bi.isCheckbox)
|
||||
bi.checked = SendMessage(bi.hWnd, BM_GETCHECK, 0, 0)==BST_CHECKED;
|
||||
bi.synchData();
|
||||
if (bi.callBack || bi.handler) {
|
||||
if (bi.callBack || bi.hasEventHandler()) {
|
||||
setWaitCursor(true);
|
||||
if (!bi.handleEvent(*this, GUI_BUTTON) && bi.callBack)
|
||||
bi.callBack(this, GUI_BUTTON, &bi); //it may be destroyed here...
|
||||
@ -3027,10 +3029,8 @@ void gdioutput::doEnter() {
|
||||
HWND hWnd=GetFocus();
|
||||
|
||||
for (list<ButtonInfo>::iterator it=BI.begin(); it!=BI.end(); ++it)
|
||||
if (it->isDefaultButton() && (it->callBack || it->handler)) {
|
||||
if (it->handler)
|
||||
it->handleEvent(*this, GUI_BUTTON);
|
||||
else
|
||||
if (it->isDefaultButton()) {
|
||||
if (!it->handleEvent(*this, GUI_BUTTON) && it->callBack)
|
||||
it->callBack(this, GUI_BUTTON, &*it);
|
||||
return;
|
||||
}
|
||||
@ -3038,13 +3038,11 @@ void gdioutput::doEnter() {
|
||||
list<InputInfo>::iterator it;
|
||||
|
||||
for(it=II.begin(); it != II.end(); ++it)
|
||||
if (it->hWnd==hWnd && (it->callBack || it->handler)){
|
||||
if (it->hWnd==hWnd && (it->hasEventHandler() || it->callBack)){
|
||||
TCHAR bf[1024];
|
||||
GetWindowText(hWnd, bf, 1024);
|
||||
it->text=bf;
|
||||
if (it->handler)
|
||||
it->handleEvent(*this, GUI_INPUT);
|
||||
else
|
||||
it->text = bf;
|
||||
if (!it->handleEvent(*this, GUI_INPUT))
|
||||
it->callBack(this, GUI_INPUT, &*it);
|
||||
return;
|
||||
}
|
||||
@ -3139,10 +3137,8 @@ void gdioutput::doEscape()
|
||||
tit->table->escape(*this);
|
||||
|
||||
for (list<ButtonInfo>::iterator it=BI.begin(); it!=BI.end(); ++it) {
|
||||
if (it->isCancelButton() && (it->callBack || it->handler) ) {
|
||||
if (it->handler)
|
||||
it->handleEvent(*this, GUI_BUTTON);
|
||||
else
|
||||
if (it->isCancelButton() && (it->callBack || it->hasEventHandler()) ) {
|
||||
if (!it->handleEvent(*this, GUI_BUTTON))
|
||||
it->callBack(this, GUI_BUTTON, &*it);
|
||||
return;
|
||||
}
|
||||
@ -3517,15 +3513,15 @@ BaseInfo *gdioutput::setText(const char *id, const wstring &text, bool Update, i
|
||||
|
||||
bool gdioutput::insertText(const string &id, const wstring &text)
|
||||
{
|
||||
for (list<InputInfo>::iterator it=II.begin();
|
||||
it != II.end(); ++it) {
|
||||
if (it->id==id) {
|
||||
for (list<InputInfo>::iterator it = II.begin();
|
||||
it != II.end(); ++it) {
|
||||
if (it->id == id) {
|
||||
SetWindowText(it->hWnd, text.c_str());
|
||||
it->text = text;
|
||||
|
||||
if (it->handler)
|
||||
if (it->hasEventHandler())
|
||||
it->handleEvent(*this, GUI_INPUT);
|
||||
else if (it->callBack)
|
||||
else if (it->callBack)
|
||||
it->callBack(this, GUI_INPUT, &*it);
|
||||
|
||||
return true;
|
||||
@ -4385,9 +4381,6 @@ void gdioutput::RenderString(TextInfo &ti, HDC hDC) {
|
||||
h = ti.textRect.bottom - ti.textRect.top;
|
||||
|
||||
image.drawImage(imgId, Image::ImageMethod::Default, hDC, rc.left, rc.top, w, h);
|
||||
|
||||
//width = image.getWidth(imgId);
|
||||
//height = image.getHeight(imgId);
|
||||
}
|
||||
}
|
||||
if (!fixedRect) {
|
||||
@ -5503,7 +5496,7 @@ int gdioutput::sendCtrlMessage(const string &id)
|
||||
{
|
||||
for (list<ButtonInfo>::iterator it=BI.begin(); it != BI.end(); ++it) {
|
||||
if (id==it->id) {
|
||||
if (it->handler)
|
||||
if (it->hasEventHandler())
|
||||
return it->handleEvent(*this, GUI_BUTTON);
|
||||
else if (it->callBack)
|
||||
return it->callBack(this, GUI_BUTTON, &*it); //it may be destroyed here...
|
||||
@ -7201,11 +7194,11 @@ string gdioutput::dbPress(const string &id, int extra) {
|
||||
if (it->isCheckbox) {
|
||||
check(id, !isChecked(id));
|
||||
}
|
||||
else if(!it->callBack && !it->handler)
|
||||
else if(!it->callBack && !it->hasEventHandler())
|
||||
throw meosException("Button " + id + " is not active.");
|
||||
|
||||
wstring val = it->text;
|
||||
if (it->handler)
|
||||
if (it->hasEventHandler())
|
||||
it->handleEvent(*this, GUI_BUTTON);
|
||||
else if (it->callBack)
|
||||
it->callBack(this, GUI_BUTTON, &*it); //it may be destroyed here...
|
||||
@ -7229,11 +7222,11 @@ string gdioutput::dbPress(const string &id, const char *extra) {
|
||||
if (it->isCheckbox) {
|
||||
check(id, !isChecked(id));
|
||||
}
|
||||
else if(!it->callBack && !it->handler)
|
||||
else if(!it->callBack && !it->hasEventHandler())
|
||||
throw meosException("Button " + id + " is not active.");
|
||||
|
||||
wstring val = it->text;
|
||||
if (it->handler)
|
||||
if (it->hasEventHandler())
|
||||
it->handleEvent(*this, GUI_BUTTON);
|
||||
else if (it->callBack)
|
||||
it->callBack(this, GUI_BUTTON, &*it); //it may be destroyed here...
|
||||
@ -7272,12 +7265,12 @@ string gdioutput::dbSelect(const string &id, int data) {
|
||||
|
||||
void gdioutput::internalSelect(ListBoxInfo &bi) {
|
||||
bi.syncData();
|
||||
if (bi.callBack || bi.handler) {
|
||||
if (bi.callBack || bi.handler || bi.managedHandler) {
|
||||
setWaitCursor(true);
|
||||
hasCleared = false;
|
||||
try {
|
||||
bi.writeLock = true;
|
||||
if (bi.handler)
|
||||
if (bi.hasEventHandler())
|
||||
bi.handleEvent(*this, GUI_LISTBOX);
|
||||
else
|
||||
bi.callBack(this, GUI_LISTBOX, &bi); //it may be destroyed here... Then hasCleared is set.
|
||||
@ -7304,7 +7297,7 @@ void gdioutput::dbInput(const string &id, const string &text) {
|
||||
SetWindowText(it->hWnd, widen(text).c_str());
|
||||
it->text = widen(text);
|
||||
it->data = -1;
|
||||
if (it->handler)
|
||||
if (it->hasEventHandler())
|
||||
it->handleEvent(*this, GUI_COMBO);
|
||||
else if (it->callBack)
|
||||
it->callBack(this, GUI_COMBO, &*it); //it may be destroyed here...
|
||||
@ -7319,7 +7312,7 @@ void gdioutput::dbInput(const string &id, const string &text) {
|
||||
|
||||
it->text = widen(text);
|
||||
SetWindowText(it->hWnd, widen(text).c_str());
|
||||
if (it->handler)
|
||||
if (it->hasEventHandler())
|
||||
it->handleEvent(*this, GUI_INPUT);
|
||||
else if (it->callBack)
|
||||
it->callBack(this, GUI_INPUT, &*it);
|
||||
@ -7357,7 +7350,7 @@ void gdioutput::dbDblClick(const string &id, int data) {
|
||||
if (!IsWindowEnabled(it->hWnd))
|
||||
throw meosException("Selection " + id + " is not active.");
|
||||
selectItemByData(id, data);
|
||||
if (it->handler)
|
||||
if (it->hasEventHandler())
|
||||
it->handleEvent(*this, GUI_LISTBOXSELECT);
|
||||
else if (it->callBack)
|
||||
it->callBack(this, GUI_LISTBOXSELECT, &*it); //it may be destroyed here...
|
||||
|
||||
@ -205,7 +205,7 @@ class InfoCompetitor : public InfoBaseCompetitor {
|
||||
class InfoTeam : public InfoBaseCompetitor {
|
||||
protected:
|
||||
// The outer level holds legs, the inner level holds (parallel/patrol) runners on each leg.
|
||||
vector< vector<int> > competitors;
|
||||
vector<vector<int>> competitors;
|
||||
public:
|
||||
bool synchronize(oTeam &t);
|
||||
void serialize(xmlbuffer &xml, bool diffOnly) const;
|
||||
|
||||
@ -2417,7 +2417,10 @@ pRunner IOF30Interface::readPersonResult(gdioutput &gdi, pClass pc, xmlobject &x
|
||||
wstring s;
|
||||
for (auto &split : splits) {
|
||||
int code = split.getObjectInt("ControlCode");
|
||||
int time = split.getObjectInt("Time");
|
||||
wstring out;
|
||||
split.getObjectString("Time", out);
|
||||
double t = _wtof(out.c_str());
|
||||
int time = int(t * timeConstSecond);
|
||||
split.getObjectString("status", s);
|
||||
if (s != L"missing")
|
||||
card->addPunch(code, st + time, 0, 0);
|
||||
|
||||
@ -463,6 +463,8 @@ int APIENTRY WinMain(HINSTANCE hInstance,
|
||||
gdi_main->init(hWndWorkspace, hWndMain, hMainTab);
|
||||
gdi_main->getTabs().get(TCmpTab)->loadPage(*gdi_main);
|
||||
|
||||
image.loadImage(IDI_MEOSEDIT, Image::ImageMethod::Default);
|
||||
|
||||
autoTask = new AutoTask(hWndMain, *gEvent, *gdi_main);
|
||||
|
||||
autoTask->setTimers();
|
||||
|
||||
@ -53,6 +53,7 @@ IDB_ECO BITMAP "bmp00001.bmp"
|
||||
IDI_SPLASHIMAGE PNG "meos.png"
|
||||
IDI_MEOSIMAGE PNG "title.png"
|
||||
IDI_MEOSINFO PNG "info24.png"
|
||||
IDI_MEOSEDIT PNG "edit.png"
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United States) resources
|
||||
|
||||
|
||||
@ -919,16 +919,10 @@ string itos(uint64_t i)
|
||||
return bf;
|
||||
}
|
||||
|
||||
|
||||
bool filterMatchString(const string &c, const char *filt_lc)
|
||||
{
|
||||
if (filt_lc[0] == 0)
|
||||
return true;
|
||||
char key[2048];
|
||||
strcpy_s(key, c.c_str());
|
||||
CharLowerBuffA(key, c.length());
|
||||
|
||||
return strstr(key, filt_lc)!=0;
|
||||
void prepareMatchString(wchar_t* data_c, int size) {
|
||||
CharLowerBuff(data_c, size);
|
||||
for (int j = 0; j < size; j++)
|
||||
data_c[j] = toLowerStripped(data_c[j]);
|
||||
}
|
||||
|
||||
bool filterMatchString(const wstring &c, const wchar_t *filt_lc, int &score) {
|
||||
@ -937,7 +931,11 @@ bool filterMatchString(const wstring &c, const wchar_t *filt_lc, int &score) {
|
||||
return true;
|
||||
wchar_t key[2048];
|
||||
wcscpy_s(key, c.c_str());
|
||||
CharLowerBuff(key, c.length());
|
||||
int cl = c.length();
|
||||
CharLowerBuff(key, cl);
|
||||
for (int j = 0; j < cl; j++)
|
||||
key[j] = toLowerStripped(key[j]);
|
||||
|
||||
bool match = wcsstr(key, filt_lc) != 0;
|
||||
if (match) {
|
||||
while (filt_lc[score] && key[score] && filt_lc[score] == key[score])
|
||||
@ -1259,14 +1257,14 @@ int toLowerStripped(wchar_t c) {
|
||||
return c;
|
||||
|
||||
static wchar_t *map = 0;
|
||||
if (map == 0) {
|
||||
if (map == nullptr) {
|
||||
map = new wchar_t[65536];
|
||||
for (int i = 0; i < 65536; i++)
|
||||
map[i] = i;
|
||||
|
||||
setChar(map, L'Å', L'å');
|
||||
setChar(map, L'Ä', L'ä');
|
||||
setChar(map, L'Ö', L'ö');
|
||||
setChar(map, L'Å', L'a');
|
||||
setChar(map, L'Ä', L'a');
|
||||
setChar(map, L'Ö', L'o');
|
||||
|
||||
setChar(map, L'É', L'e');
|
||||
setChar(map, L'é', L'e');
|
||||
@ -1289,6 +1287,8 @@ int toLowerStripped(wchar_t c) {
|
||||
setChar(map, L'ñ', L'n');
|
||||
setChar(map, L'Ñ', L'n');
|
||||
|
||||
setChar(map, L'ä', L'a');
|
||||
setChar(map, L'å', L'a');
|
||||
setChar(map, L'á', L'a');
|
||||
setChar(map, L'Á', L'a');
|
||||
setChar(map, L'à', L'a');
|
||||
@ -1315,19 +1315,29 @@ int toLowerStripped(wchar_t c) {
|
||||
setChar(map, L'Õ', L'o');
|
||||
setChar(map, L'ô', L'o');
|
||||
setChar(map, L'Ô', L'o');
|
||||
setChar(map, L'ö', L'o');
|
||||
|
||||
setChar(map, L'ý', L'y');
|
||||
setChar(map, L'Ý', L'Y');
|
||||
setChar(map, L'ÿ', L'y');
|
||||
|
||||
setChar(map, L'Æ', L'a');
|
||||
setChar(map, L'æ', L'a');
|
||||
|
||||
setChar(map, L'Æ', L'ä');
|
||||
setChar(map, L'æ', L'ä');
|
||||
|
||||
setChar(map, L'Ø', L'ö');
|
||||
setChar(map, L'ø', L'ö');
|
||||
setChar(map, L'Ø', L'o');
|
||||
setChar(map, L'ø', L'o');
|
||||
|
||||
setChar(map, L'Ç', L'c');
|
||||
setChar(map, L'ç', L'c');
|
||||
|
||||
wstring srcEx = L"Ă㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻĽľĿŀŁł"
|
||||
L"ŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽž";
|
||||
wstring dstEx = L"aaaaccccccccddddeeeeeeeeeegggggggghhhhiiiiiiiiiijjjjkkklllllllll"
|
||||
L"nnnnnnnnnooooooaarrrrrrssssssssttttttuuuuuuuuuuuuwwyyyzzzzzz";
|
||||
|
||||
assert(srcEx.size() == dstEx.size());
|
||||
for (int j = 0; j < srcEx.size(); j++)
|
||||
setChar(map, srcEx[j], dstEx[j]);
|
||||
}
|
||||
int a = map[c];
|
||||
return a;
|
||||
|
||||
@ -152,10 +152,13 @@ wstring itow(int64_t i);
|
||||
wstring itow(uint64_t i);
|
||||
|
||||
|
||||
///Lower case match (filt_lc must be lc)
|
||||
bool filterMatchString(const string &c, const char *filt_lc);
|
||||
///Lower case match (filt_lc must be lc and stripped of accents)
|
||||
bool filterMatchString(const wstring &c, const wchar_t *filt_lc, int &score);
|
||||
|
||||
/** To lower case and strip accants */
|
||||
void prepareMatchString(wchar_t* data_c, int size);
|
||||
|
||||
|
||||
bool matchNumber(int number, const wchar_t *key);
|
||||
|
||||
int getMeosBuild();
|
||||
|
||||
@ -25,12 +25,12 @@
|
||||
|
||||
//ABCDEFGHIJKLMNOP
|
||||
int getMeosBuild() {
|
||||
string revision("$Rev: 1263 $");
|
||||
string revision("$Rev: 1266 $");
|
||||
return 174 + atoi(revision.substr(5, string::npos).c_str());
|
||||
}
|
||||
|
||||
wstring getMeosDate() {
|
||||
wstring date(L"$Date: 2023-05-12 16:11:34 +0200 (fre, 12 maj 2023) $");
|
||||
wstring date(L"$Date: 2023-06-01 22:17:24 +0200 (tor, 01 jun 2023) $");
|
||||
return date.substr(7,10);
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ wstring getBuildType() {
|
||||
}
|
||||
|
||||
wstring getMajorVersion() {
|
||||
return L"3.9";
|
||||
return L"4.0";
|
||||
}
|
||||
|
||||
wstring getMeosFullVersion() {
|
||||
|
||||
@ -2198,6 +2198,7 @@ void MetaList::initSymbols() {
|
||||
typeToSymbol[lCourseUsage] = L"CourseUsage";
|
||||
typeToSymbol[lCourseUsageNoVacant] = L"CourseUsageNoVacant";
|
||||
typeToSymbol[lCourseClasses] = L"CourseClasses";
|
||||
typeToSymbol[lCourseNumControls] = L"CourseNumControls";
|
||||
typeToSymbol[lCourseShortening] = L"CourseShortening";
|
||||
typeToSymbol[lRunnerName] = L"RunnerName";
|
||||
typeToSymbol[lRunnerGivenName] = L"RunnerGivenName";
|
||||
@ -2301,18 +2302,26 @@ void MetaList::initSymbols() {
|
||||
typeToSymbol[lPunchNamedTime] = L"PunchNamedTime";
|
||||
typeToSymbol[lPunchName] = L"PunchName";
|
||||
typeToSymbol[lPunchNamedSplit] = L"PunchNamedSplit";
|
||||
typeToSymbol[lPunchTeamTotalNamedTime] = L"PunchTeamTotalNamedTime";
|
||||
|
||||
typeToSymbol[lPunchTime] = L"PunchTime";
|
||||
typeToSymbol[lPunchTeamTime] = L"PunchTeamTime";
|
||||
|
||||
typeToSymbol[lPunchControlNumber] = L"PunchControlNumber";
|
||||
typeToSymbol[lPunchControlCode] = L"PunchControlCode";
|
||||
typeToSymbol[lPunchLostTime] = L"PunchLostTime";
|
||||
typeToSymbol[lPunchControlPlace] = L"PunchControlPlace";
|
||||
typeToSymbol[lPunchControlPlaceAcc] = L"PunchControlPlaceAcc";
|
||||
typeToSymbol[lPunchControlPlaceTeamAcc] = L"PunchControlPlaceTeamAcc";
|
||||
|
||||
typeToSymbol[lPunchSplitTime] = L"PunchSplitTime";
|
||||
typeToSymbol[lPunchTotalTime] = L"PunchTotalTime";
|
||||
typeToSymbol[lPunchTeamTotalTime] = L"PunchTeamTotalTime";
|
||||
|
||||
typeToSymbol[lPunchAbsTime] = L"PunchAbsTime";
|
||||
typeToSymbol[lPunchTotalTimeAfter] = L"PunchTotalTimeAfter";
|
||||
typeToSymbol[lPunchTeamTotalTimeAfter] = L"PunchTeamTotalTimeAfter";
|
||||
|
||||
typeToSymbol[lPunchTimeSinceLast] = L"PunchTimeSinceLast";
|
||||
|
||||
typeToSymbol[lRogainingPunch] = L"RogainingPunch";
|
||||
@ -3461,7 +3470,7 @@ void MetaList::getAutoComplete(const wstring& w, vector<AutoCompleteRecord>& rec
|
||||
s_lc[j].resize(ws[j].size() + 1);
|
||||
ws[j] = trim(ws[j]);
|
||||
wcscpy_s(s_lc[j].data(), s_lc[j].size(), ws[j].c_str());
|
||||
CharLowerBuff(s_lc[j].data(), ws[j].length());
|
||||
prepareMatchString(s_lc[j].data(), ws[j].length());
|
||||
}
|
||||
|
||||
wstring tl;
|
||||
|
||||
@ -434,6 +434,10 @@ public:
|
||||
|
||||
static void fillSymbols(vector < pair<wstring, size_t>> &symb);
|
||||
|
||||
static const map<SortOrder, string>& getOrderToSymbol() {
|
||||
return orderToSymbol;
|
||||
}
|
||||
|
||||
friend class MetaListPost;
|
||||
};
|
||||
|
||||
@ -526,6 +530,6 @@ public:
|
||||
void synchronizeTo(MetaListContainer &dst) const;
|
||||
|
||||
bool interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par, oListInfo &li) const;
|
||||
|
||||
|
||||
void enumerateLists(vector< pair<wstring, pair<string, wstring> > > &out) const;
|
||||
};
|
||||
|
||||
@ -815,7 +815,7 @@ wstring oCard::getCardVoltage() const {
|
||||
}
|
||||
|
||||
wstring oCard::getCardVoltage(int miliVolt) {
|
||||
if (miliVolt == 0)
|
||||
if (miliVolt <= 10)
|
||||
return L"";
|
||||
int vi = miliVolt / 1000;
|
||||
int vd = (miliVolt % 1000) / 10;
|
||||
@ -830,9 +830,9 @@ oCard::BatteryStatus oCard::isCriticalCardVoltage() const {
|
||||
}
|
||||
|
||||
oCard::BatteryStatus oCard::isCriticalCardVoltage(int miliVolt) {
|
||||
if (miliVolt > 0 && miliVolt < 2445)
|
||||
if (miliVolt > 10 && miliVolt < 2445)
|
||||
return BatteryStatus::Bad;
|
||||
else if (miliVolt > 0 && miliVolt <= 2710)
|
||||
else if (miliVolt > 10 && miliVolt <= 2710)
|
||||
return BatteryStatus::Warning;
|
||||
|
||||
return BatteryStatus::OK;
|
||||
|
||||
116
code/oClass.cpp
116
code/oClass.cpp
@ -404,7 +404,7 @@ int oClass::getNumRunners(bool checkFirstLeg, bool noCountVacant, bool noCountNo
|
||||
}
|
||||
}
|
||||
string key = getCountTypeKey(checkFirstLeg ? 0 : -1,
|
||||
noCountNotCompeting ? CountKeyType::All : CountKeyType::IncludeNotCompeting,
|
||||
noCountNotCompeting ? CountKeyType::AllCompeting : CountKeyType::IncludeNotCompeting,
|
||||
!noCountVacant);
|
||||
|
||||
auto res = tTypeKeyToRunnerCount.second.find(key);
|
||||
@ -419,7 +419,7 @@ int oClass::getNumRunners(bool checkFirstLeg, bool noCountVacant, bool noCountNo
|
||||
continue;
|
||||
if (noCountVacant && r.isVacant())
|
||||
continue;
|
||||
if (noCountNotCompeting && r.getStatus() == StatusNotCompetiting)
|
||||
if (noCountNotCompeting && (r.getStatus() == StatusNotCompetiting || r.getStatus() == StatusCANCEL))
|
||||
continue;
|
||||
|
||||
int id = r.getClassId(true);
|
||||
@ -3371,6 +3371,16 @@ int oClass::getLegPlace(int ifrom, int ito, int time) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
int oClass::getAccLegControlLeader(int teamLeg, int courseControlId) const {
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int oClass::getAccLegControlPlace(int teamLeg, int courseControlId, int time) const {
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void oClass::insertAccLegPlace(int courseId, int controlNo, int time, int place)
|
||||
{ /*
|
||||
char bf[256];
|
||||
@ -3441,7 +3451,6 @@ int oClass::getAccLegPlace(int courseId, int controlNo, int time) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void oClass::calculateSplits() {
|
||||
clearSplitAnalysis();
|
||||
set<pCourse> cSet;
|
||||
@ -3460,33 +3469,50 @@ void oClass::calculateSplits() {
|
||||
LegResult legBestTime;
|
||||
vector<pRunner> rCls;
|
||||
oe->getRunners(Id, -1, rCls, false);
|
||||
/*
|
||||
if (isQualificationFinalBaseClass() || isQualificationFinalBaseClass()) {
|
||||
|
||||
for (auto &r : oe->Runners) {
|
||||
if (!r.isRemoved() && r.getClassRef(true) == this)
|
||||
rCls.push_back(&r);
|
||||
|
||||
for (pRunner it : rCls) {
|
||||
pCourse tpc = it->getCourse(false);
|
||||
if (tpc == nullptr)
|
||||
continue;
|
||||
cSet.insert(tpc);
|
||||
}
|
||||
|
||||
map<int, vector<pRunner>> rClsCrs;
|
||||
if (cSet.size() > 1) {
|
||||
for (pRunner it : rCls) {
|
||||
pCourse tpc = it->getCourse(false);
|
||||
if (tpc)
|
||||
rClsCrs[tpc->getId()].push_back(it);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (auto &r : oe->Runners) {
|
||||
if (!r.isRemoved() && r.Class == this)
|
||||
rCls.push_back(&r);
|
||||
}
|
||||
}*/
|
||||
|
||||
for (set<pCourse>::iterator cit = cSet.begin(); cit!= cSet.end(); ++cit) {
|
||||
pCourse pc = *cit;
|
||||
bool multiLeg = getNumStages() > 1; // Perhaps ignore parallell legs...
|
||||
|
||||
if (multiLeg) {
|
||||
teamLegCourseControlToLeaderPlace.resize(getNumStages());
|
||||
for (auto& lp : teamLegCourseControlToLeaderPlace)
|
||||
lp.clear();
|
||||
}
|
||||
else {
|
||||
teamLegCourseControlToLeaderPlace.clear();
|
||||
}
|
||||
|
||||
for (pCourse pc : cSet) {
|
||||
// Store all split times in a matrix
|
||||
const unsigned nc = pc->getNumControls();
|
||||
if (nc == 0)
|
||||
return;
|
||||
|
||||
vector< vector<int> > splits(nc+1);
|
||||
vector< vector<int> > splitsAcc(nc+1);
|
||||
vector<bool> acceptMissingPunch(nc+1, true);
|
||||
vector<vector<int>> splits(nc+1);
|
||||
vector<vector<int>> splitsAcc(nc+1);
|
||||
vector<int8_t> acceptMissingPunch(nc+1, true);
|
||||
vector<pRunner>* rList;
|
||||
if (rClsCrs.empty())
|
||||
rList = &rCls;
|
||||
else
|
||||
rList = &rClsCrs[pc->getId()];
|
||||
|
||||
for (pRunner it : rCls) {
|
||||
for (pRunner it : *rList) {
|
||||
pCourse tpc = it->getCourse(false);
|
||||
if (tpc != pc || tpc == 0)
|
||||
continue;
|
||||
@ -3504,7 +3530,7 @@ void oClass::calculateSplits() {
|
||||
}
|
||||
}
|
||||
|
||||
for (pRunner it : rCls) {
|
||||
for (pRunner it : *rList) {
|
||||
pCourse tpc = it->getCourse(false);
|
||||
|
||||
if (tpc != pc)
|
||||
@ -3513,17 +3539,46 @@ void oClass::calculateSplits() {
|
||||
const vector<SplitData> &sp = it->getSplitTimes(true);
|
||||
const int s = min<int>(nc, sp.size());
|
||||
|
||||
int off = 0;
|
||||
unordered_map<int, PlaceTime>* teamAccTimes = nullptr;
|
||||
if (multiLeg && it->tInTeam)
|
||||
off = it->tInTeam->getTotalRunningTimeAtLegStart(it->tLeg, false);
|
||||
|
||||
if (off > 0 && it->tLeg < teamLegCourseControlToLeaderPlace.size())
|
||||
teamAccTimes = &teamLegCourseControlToLeaderPlace[it->tLeg];
|
||||
|
||||
vector<int> &tLegTimes = it->tLegTimes;
|
||||
tLegTimes.resize(nc + 1);
|
||||
bool ok = true;
|
||||
|
||||
// Acc team finish time
|
||||
if (teamAccTimes && it->FinishTime > 0 && (it->tStatus == StatusOK || it->tStatus == StatusUnknown)) {
|
||||
int ccId = oPunch::PunchFinish;
|
||||
int t = it->getRunningTime(false);
|
||||
auto& res = (*teamAccTimes)[ccId];
|
||||
if (res.leader <= 0 || res.leader > t + off)
|
||||
res.leader = t + off;
|
||||
// Count times
|
||||
++res.timeToPlace[t + off];
|
||||
}
|
||||
|
||||
for (int k = 0; k < s; k++) {
|
||||
if (sp[k].getTime(true) > 0) {
|
||||
if (ok) {
|
||||
// Store accumulated times
|
||||
int t = sp[k].getTime(true) - it->tStartTime;
|
||||
if (it->tStartTime>0 && t>0)
|
||||
if (it->tStartTime > 0 && t > 0) {
|
||||
splitsAcc[k].push_back(t);
|
||||
if (teamAccTimes) {
|
||||
int ccId = pc->getCourseControlId(k);
|
||||
auto& res = (*teamAccTimes)[ccId];
|
||||
if (res.leader <= 0 || res.leader > t + off)
|
||||
res.leader = t + off;
|
||||
|
||||
// Count times
|
||||
++res.timeToPlace[t + off];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (k == 0) { // start -> first
|
||||
@ -3636,8 +3691,7 @@ void oClass::calculateSplits() {
|
||||
}
|
||||
}
|
||||
|
||||
for (set<pCourse>::iterator cit = cSet.begin(); cit != cSet.end(); ++cit) {
|
||||
pCourse pc = *cit;
|
||||
for (pCourse pc : cSet) {
|
||||
const unsigned nc = pc->getNumControls();
|
||||
vector<int> normRes(nc+1);
|
||||
vector<int> bestRes(nc+1);
|
||||
@ -3655,6 +3709,18 @@ void oClass::calculateSplits() {
|
||||
swap(tSplitAnalysisData[pc->getId()], normRes);
|
||||
swap(tCourseLegLeaderTime[pc->getId()], bestRes);
|
||||
}
|
||||
|
||||
// Convert number of competitors with time to place
|
||||
for (auto& courseControlLeaderPlace : teamLegCourseControlToLeaderPlace) {
|
||||
for (auto& leaderPlace : courseControlLeaderPlace) {
|
||||
int place = 1;
|
||||
for (auto& numTimes : leaderPlace.second.timeToPlace) {
|
||||
int num = numTimes.second;
|
||||
numTimes.second = place;
|
||||
place += num;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool oClass::isRogaining() const {
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include "inthashmap.h"
|
||||
class oClass;
|
||||
typedef oClass* pClass;
|
||||
@ -260,9 +261,20 @@ protected:
|
||||
inthashmap *tLegTimeToPlace;
|
||||
inthashmap *tLegAccTimeToPlace;
|
||||
|
||||
struct PlaceTime {
|
||||
int leader = -1;
|
||||
map<int, int> timeToPlace;
|
||||
};
|
||||
|
||||
vector<unordered_map<int, PlaceTime>> teamLegCourseControlToLeaderPlace;
|
||||
|
||||
void insertLegPlace(int from, int to, int time, int place);
|
||||
void insertAccLegPlace(int courseId, int controlNo, int time, int place);
|
||||
|
||||
/** Get relay/team accumulated leader time/place at control. */
|
||||
int getAccLegControlLeader(int teamLeg, int courseControlId) const;
|
||||
int getAccLegControlPlace(int teamLeg, int courseControlId, int time) const;
|
||||
|
||||
// For sub split times
|
||||
int tLegLeaderTime;
|
||||
mutable int tNoTiming;
|
||||
@ -357,7 +369,7 @@ protected:
|
||||
mutable pair<int, map<string, int>> tTypeKeyToRunnerCount;
|
||||
|
||||
enum CountKeyType {
|
||||
All,
|
||||
AllCompeting,
|
||||
Finished,
|
||||
ExpectedStarting,
|
||||
DNS,
|
||||
@ -620,7 +632,7 @@ public:
|
||||
bool hasTrueMultiCourse() const;
|
||||
|
||||
unsigned getNumStages() const {return MultiCourse.size();}
|
||||
/** Get the set of true legs, identifying parallell legs etc. Returns indecs into
|
||||
/** Get the set of true legs, identifying parallell legs etc. Returns indices into
|
||||
legInfo of the last leg of the true leg (first), and true leg (second).*/
|
||||
struct TrueLegInfo {
|
||||
protected:
|
||||
|
||||
@ -653,7 +653,8 @@ const vector< pair<wstring, size_t> > &oEvent::getCourses(vector<pair<wstring, s
|
||||
|
||||
vector<wchar_t> filt_lc(filter.length() + 1);
|
||||
wcscpy_s(filt_lc.data(), filt_lc.size(), filter.c_str());
|
||||
CharLowerBuff(filt_lc.data(), filter.length());
|
||||
prepareMatchString(filt_lc.data(), filter.length());
|
||||
|
||||
int score;
|
||||
wstring b;
|
||||
for (size_t k = 0; k < ac.size(); k++) {
|
||||
|
||||
144
code/oEvent.cpp
144
code/oEvent.cpp
@ -70,7 +70,7 @@
|
||||
extern Image image;
|
||||
|
||||
//Version of database
|
||||
int oEvent::dbVersion = 90;
|
||||
int oEvent::dbVersion = 91;
|
||||
|
||||
bool oEvent::useSubSecond() const {
|
||||
if (useSubsecondsVersion == dataRevision)
|
||||
@ -540,6 +540,8 @@ oEvent::oEvent(gdioutput &gdi):oBase(0), gdibase(gdi)
|
||||
oEventData->addVariableString("MergeTag", 12, "Tag");
|
||||
oEventData->addVariableString("MergeInfo", "MergeInfo");
|
||||
oEventData->addVariableString("SplitPrint", 40, "Sträcktidslista"); // Id from MetaListContainer::getUniqueId
|
||||
oEventData->addVariableInt("NoVacantBib", oDataContainer::oIS8U, "Inga vakanta nummerlappar");
|
||||
|
||||
oEventData->initData(this, dataSize);
|
||||
|
||||
oClubData=new oDataContainer(oClub::dataSize);
|
||||
@ -4781,7 +4783,7 @@ bool oEvent::hasTeam() const
|
||||
return Teams.size() > 0;
|
||||
}
|
||||
|
||||
void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
|
||||
void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber, bool assignToVacant) {
|
||||
if ( !classHasTeams(ClassId) ) {
|
||||
sortRunners(ClassStartTimeClub);
|
||||
oRunnerList::iterator it;
|
||||
@ -4804,6 +4806,8 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
|
||||
if (it->isRemoved())
|
||||
continue;
|
||||
if ( (ClassId==0 || it->getClassId(true)==ClassId) && (it->legToRun()==leg || leg == -1)) {
|
||||
if (!assignToVacant && it->isVacant())
|
||||
continue;
|
||||
wchar_t bib[32];
|
||||
swprintf_s(bib, pattern, num);
|
||||
pClass pc = it->getClassRef(true);
|
||||
@ -4832,6 +4836,8 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
|
||||
for (auto it = Teams.begin(); it != Teams.end(); ++it) {
|
||||
if (it->isRemoved())
|
||||
continue;
|
||||
if (!assignToVacant && it->isVacant())
|
||||
continue;
|
||||
if (ClassId == 0 || it->getClassId(false) == ClassId) {
|
||||
if (it->getClassRef(false) && it->getClassRef(false)->getBibMode() != BibFree) {
|
||||
for (size_t i = 0; i < it->Runners.size(); i++) {
|
||||
@ -4847,7 +4853,7 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
|
||||
}
|
||||
}
|
||||
|
||||
sortTeams(ClassStartTime, 0, true); // Sort on first leg starttime and sortindex
|
||||
sortTeams(ClassStartTimeClub, 0, true); // Sort on first leg starttime and sortindex
|
||||
|
||||
if (!firstNumber.empty()) {
|
||||
wchar_t pattern[32];
|
||||
@ -4856,6 +4862,8 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
|
||||
for (auto it=Teams.begin(); it != Teams.end(); ++it) {
|
||||
if (it->isRemoved())
|
||||
continue;
|
||||
if (!assignToVacant && it->isVacant())
|
||||
continue;
|
||||
|
||||
if (ClassId == 0 || it->getClassId(false) == ClassId) {
|
||||
wchar_t bib[32];
|
||||
@ -4887,6 +4895,8 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
|
||||
}
|
||||
|
||||
void oEvent::addAutoBib() {
|
||||
bool noBibToVacant = oe->getDCI().getInt("NoVacantBib") != 0;
|
||||
|
||||
sortRunners(ClassStartTimeClub);
|
||||
oRunnerList::iterator it;
|
||||
int clsId = -1;
|
||||
@ -4907,6 +4917,7 @@ void oEvent::addAutoBib() {
|
||||
pClass cls = tit->getClassRef(false);
|
||||
if (cls == 0)
|
||||
continue;
|
||||
|
||||
teamStartNo[tit->getId()] = tit->getStartNo();
|
||||
|
||||
wstring bibInfo = cls->getDCI().getString("Bib");
|
||||
@ -4935,7 +4946,7 @@ void oEvent::addAutoBib() {
|
||||
}
|
||||
}
|
||||
|
||||
sortTeams(ClassStartTime, 0, true); // Sort on first leg starttime and sortindex
|
||||
sortTeams(ClassStartTimeClub, 0, true); // Sort on first leg starttime and sortindex
|
||||
map<int, vector<pTeam> > cls2TeamList;
|
||||
|
||||
for (oTeamList::iterator tit = Teams.begin(); tit != Teams.end(); ++tit) {
|
||||
@ -4946,7 +4957,7 @@ void oEvent::addAutoBib() {
|
||||
}
|
||||
|
||||
map<int, vector<pRunner> > cls2RunnerList;
|
||||
for (it=Runners.begin(); it != Runners.end(); ++it) {
|
||||
for (it = Runners.begin(); it != Runners.end(); ++it) {
|
||||
if (it->isRemoved() || !it->getClassId(false))
|
||||
continue;
|
||||
int clsId = it->getClassId(true);
|
||||
@ -5015,17 +5026,23 @@ void oEvent::addAutoBib() {
|
||||
else {
|
||||
bool lockedForking = cls->lockedForking();
|
||||
for (size_t k = 0; k < tl.size(); k++) {
|
||||
wchar_t buff[32];
|
||||
swprintf_s(buff, pattern, number);
|
||||
|
||||
if (lockedForking) {
|
||||
tl[k]->setBib(buff, number, false);
|
||||
tl[k]->setStartNo(teamStartNo[tl[k]->getId()], ChangeType::Update);
|
||||
if (noBibToVacant && tl[k]->isVacant()) {
|
||||
tl[k]->getDI().setString("Bib", L""); //Remove only bib
|
||||
}
|
||||
else {
|
||||
tl[k]->setBib(buff, number, true);
|
||||
wchar_t buff[32];
|
||||
swprintf_s(buff, pattern, number);
|
||||
|
||||
if (lockedForking) {
|
||||
tl[k]->setBib(buff, number, false);
|
||||
tl[k]->setStartNo(teamStartNo[tl[k]->getId()], ChangeType::Update);
|
||||
}
|
||||
else {
|
||||
tl[k]->setBib(buff, number, true);
|
||||
}
|
||||
number += interval;
|
||||
}
|
||||
number += interval;
|
||||
tl[k]->applyBibs();
|
||||
tl[k]->evaluate(ChangeType::Update);
|
||||
}
|
||||
@ -5046,7 +5063,7 @@ void oEvent::addAutoBib() {
|
||||
cls->synchronize(true);
|
||||
}
|
||||
for (size_t k = 0; k < rl.size(); k++) {
|
||||
if (pattern[0]) {
|
||||
if (pattern[0] && (!noBibToVacant || !rl[k]->isVacant())) {
|
||||
wchar_t buff[32];
|
||||
swprintf_s(buff, pattern, number);
|
||||
rl[k]->setBib(buff, number, !locked);
|
||||
@ -5267,19 +5284,73 @@ bool compareClubClassTeamName(const oRunner &a, const oRunner &b)
|
||||
return a.getClub()<b.getClub();
|
||||
}
|
||||
|
||||
void oEvent::assignCardInteractive(gdioutput &gdi, GUICALLBACK cb)
|
||||
void oEvent::assignCardInteractive(gdioutput& gdi, GUICALLBACK cb, SortOrder& orderRunners)
|
||||
{
|
||||
gdi.fillDown();
|
||||
gdi.dropLine(1);
|
||||
gdi.addString("", 2, "Tilldelning av hyrbrickor");
|
||||
|
||||
Runners.sort(compareClubClassTeamName);
|
||||
class SortUpdate : public GuiHandler {
|
||||
SortOrder& orderRunners;
|
||||
oEvent* oe;
|
||||
GUICALLBACK cb;
|
||||
public:
|
||||
SortUpdate(oEvent *oe, GUICALLBACK cb, SortOrder& orderRunners) :
|
||||
orderRunners(orderRunners), cb(cb), oe(oe) { }
|
||||
|
||||
void handle(gdioutput& gdi, BaseInfo& info, GuiEventType type) final {
|
||||
ListBoxInfo& lb = dynamic_cast<ListBoxInfo&>(info);
|
||||
orderRunners = SortOrder(lb.data);
|
||||
oe->assignCardInteractive(gdi, cb, orderRunners);
|
||||
}
|
||||
~SortUpdate() {
|
||||
}
|
||||
};
|
||||
|
||||
if (gdi.hasData("AssignCardMark")) {
|
||||
gdi.restore("AssignCardRP", false);
|
||||
}
|
||||
else {
|
||||
auto h = make_shared<SortUpdate>(this, cb, orderRunners);
|
||||
gdi.dropLine(0.5);
|
||||
gdi.addSelection("Sorting", 200, 300, nullptr, L"Sortering:").setHandler(h);
|
||||
|
||||
vector<pair<wstring, size_t> > orders;
|
||||
for (auto ord : MetaList::getOrderToSymbol()) {
|
||||
if (ord.first != SortOrder::Custom && ord.first != SortOrder::ClassDefaultResult)
|
||||
orders.push_back(make_pair(lang.tl(ord.second), ord.first));
|
||||
}
|
||||
sort(orders.begin(), orders.end());
|
||||
orders.insert(orders.begin(), make_pair(lang.tl("Standard"), SortOrder::Custom));
|
||||
|
||||
gdi.addItem("Sorting", orders);
|
||||
gdi.selectItemByData("Sorting", orderRunners);
|
||||
|
||||
gdi.dropLine();
|
||||
gdi.setData("AssignCardMark", 1);
|
||||
gdi.setRestorePoint("AssignCardRP");
|
||||
}
|
||||
|
||||
if (orderRunners == SortOrder::Custom) {
|
||||
Runners.sort(compareClubClassTeamName);
|
||||
}
|
||||
else {
|
||||
CurrentSortOrder = orderRunners;
|
||||
Runners.sort();
|
||||
}
|
||||
|
||||
oRunnerList::iterator it;
|
||||
pClub lastClub=0;
|
||||
pClub lastClub = nullptr;
|
||||
pClass lastClass = nullptr;
|
||||
|
||||
int k=0;
|
||||
for (it=Runners.begin(); it != Runners.end(); ++it) {
|
||||
const int px4 = gdi.scaleLength(4);
|
||||
const int px450 = gdi.scaleLength(450);
|
||||
|
||||
int k = 0;
|
||||
bool groupByClub = orderRunners == SortOrder::Custom || orderRunners == ClubClassStartTime;
|
||||
bool groupByClass = orderByClass(orderRunners);
|
||||
|
||||
for (it = Runners.begin(); it != Runners.end(); ++it) {
|
||||
|
||||
if (it->skip() || it->getCardNo() || it->isVacant() || it->needNoCard())
|
||||
continue;
|
||||
@ -5287,37 +5358,54 @@ void oEvent::assignCardInteractive(gdioutput &gdi, GUICALLBACK cb)
|
||||
if (it->getStatus() == StatusDNS || it->getStatus() == StatusCANCEL || it->getStatus() == StatusNotCompetiting)
|
||||
continue;
|
||||
|
||||
if (it->Club!=lastClub) {
|
||||
lastClub=it->Club;
|
||||
if (groupByClub && it->Club != lastClub) {
|
||||
lastClub = it->Club;
|
||||
gdi.dropLine(0.5);
|
||||
gdi.addString("", 1, it->getClub());
|
||||
gdi.addStringUT(1, it->getClub());
|
||||
}
|
||||
else if (groupByClass && it->Class != lastClass) {
|
||||
lastClass = it->getClassRef(true);
|
||||
gdi.dropLine(0.5);
|
||||
gdi.addStringUT(1, it->getClass(true));
|
||||
}
|
||||
|
||||
wstring r;
|
||||
if (it->Class)
|
||||
r+=it->getClass(false)+L", ";
|
||||
if (!groupByClass && it->Class)
|
||||
r += it->getClass(false) + L", ";
|
||||
|
||||
if (!groupByClub && it->Club)
|
||||
r += it->getClub() + L", ";
|
||||
|
||||
if (it->tInTeam) {
|
||||
r+=itow(it->tInTeam->getStartNo()) + L" " + it->tInTeam->getName() + L", ";
|
||||
}
|
||||
if (!it->tInTeam->getBib().empty())
|
||||
r += it->tInTeam->getBib() + L" ";
|
||||
|
||||
r += it->tInTeam->getName() + L", ";
|
||||
}
|
||||
else {
|
||||
if (!it->getBib().empty())
|
||||
r += it->getBib() + L" ";
|
||||
}
|
||||
r += it->getName() + L":";
|
||||
|
||||
gdi.fillRight();
|
||||
gdi.pushX();
|
||||
gdi.addStringUT(0, r);
|
||||
char id[24];
|
||||
sprintf_s(id, "*%d", k++);
|
||||
|
||||
gdi.addInput(max(gdi.getCX(), 450), gdi.getCY()-4,
|
||||
id, L"", 10, cb).setExtra(it->getId());
|
||||
gdi.addInput(max(gdi.getCX(), px450), gdi.getCY() - px4,
|
||||
id, L"", 10, cb).setExtra(it->getId());
|
||||
|
||||
gdi.popX();
|
||||
gdi.dropLine(1.6);
|
||||
gdi.fillDown();
|
||||
}
|
||||
|
||||
if (k==0)
|
||||
if (k == 0)
|
||||
gdi.addString("", 0, "Ingen löpare saknar bricka");
|
||||
|
||||
gdi.refresh();
|
||||
}
|
||||
|
||||
void oEvent::calcUseStartSeconds()
|
||||
|
||||
@ -726,7 +726,7 @@ public:
|
||||
inline bool useStartSeconds() const {return tUseStartSeconds;}
|
||||
void calcUseStartSeconds();
|
||||
|
||||
void assignCardInteractive(gdioutput &gdi, GUICALLBACK cb);
|
||||
void assignCardInteractive(gdioutput &gdi, GUICALLBACK cb, SortOrder& orderRunners);
|
||||
|
||||
int getPropertyInt(const char *name, int def);
|
||||
const string &getPropertyString(const char *name, const string &def);
|
||||
@ -820,7 +820,7 @@ public:
|
||||
|
||||
void checkOrderIdMultipleCourses(int ClassId);
|
||||
|
||||
void addBib(int ClassId, int leg, const wstring &firstNumber);
|
||||
void addBib(int ClassId, int leg, const wstring &firstNumber, bool assignVacant);
|
||||
void addAutoBib();
|
||||
|
||||
//Speaker functions.
|
||||
|
||||
@ -510,9 +510,12 @@ private:
|
||||
else {
|
||||
vector<pRunner> cr;
|
||||
oe->getRunners(c_it->getId(), 0, cr, false);
|
||||
for (pRunner r : cr)
|
||||
for (pRunner r : cr) {
|
||||
if (r->getStatus() == StatusNotCompetiting || r->getStatus() == StatusCANCEL)
|
||||
continue;
|
||||
if (r->getStartGroup(true) == ci.startGroupId)
|
||||
nr++;
|
||||
}
|
||||
}
|
||||
|
||||
if (ci.nVacant == -1 || !ci.nVacantSpecified || di.changedVacancyInfo) {
|
||||
@ -982,7 +985,7 @@ void oEvent::loadDrawSettings(const set<int> &classes, DrawInfo &drawInfo, vecto
|
||||
|
||||
cInfo[i].nRunners = pc->getNumRunners(true, true, true) + cInfo[i].nVacant;
|
||||
|
||||
if (cInfo[i].nRunners>0) {
|
||||
if (cInfo[i].nRunners > 0) {
|
||||
runnerPerGroup[cInfo[i].unique] += cInfo[i].nRunners;
|
||||
runnerPerCourse[cInfo[i].courseId] += cInfo[i].nRunners;
|
||||
}
|
||||
@ -996,6 +999,7 @@ void oEvent::loadDrawSettings(const set<int> &classes, DrawInfo &drawInfo, vecto
|
||||
cInfo[k].nRunnersCourse = runnerPerCourse[cInfo[k].courseId];
|
||||
}
|
||||
}
|
||||
|
||||
void oEvent::drawRemaining(DrawMethod method, bool placeAfter)
|
||||
{
|
||||
DrawType drawType = placeAfter ? DrawType::RemainingAfter : DrawType::RemainingBefore;
|
||||
@ -1770,7 +1774,7 @@ void oEvent::drawList(const vector<ClassDrawSpecification> &spec,
|
||||
for (it=Runners.begin(); it != Runners.end(); ++it) {
|
||||
int cid = it->getClassId(true);
|
||||
if (!it->isRemoved() && clsId2Ix.count(cid)) {
|
||||
if (it->getStatus() == StatusNotCompetiting)
|
||||
if (it->getStatus() == StatusNotCompetiting || it->getStatus() == StatusCANCEL)
|
||||
continue;
|
||||
int ix = clsId2Ix[cid];
|
||||
if (spec[ix].startGroup != 0 && it->getStartGroup(true) != spec[ix].startGroup)
|
||||
@ -1792,7 +1796,7 @@ void oEvent::drawList(const vector<ClassDrawSpecification> &spec,
|
||||
|
||||
for (it=Runners.begin(); it != Runners.end(); ++it) {
|
||||
if (!it->isRemoved() && clsId2Ix.count(it->getClassId(true))) {
|
||||
if (it->getStatus() == StatusNotCompetiting)
|
||||
if (it->getStatus() == StatusNotCompetiting || it->getStatus() == StatusCANCEL)
|
||||
continue;
|
||||
|
||||
int st = it->getStartTime();
|
||||
|
||||
@ -1051,8 +1051,9 @@ void oEvent::computePreliminarySplitResults(const set<int> &classes) const {
|
||||
if (ccId <= 0)
|
||||
continue;
|
||||
int crs = r->getCourse(false)->getId();
|
||||
int time = p.getTimeInt() - r->getStartTime(); //XXX Team time
|
||||
r->tOnCourseResults.emplace_back(ccId, courseCCid2CourseIx[make_pair(crs, ccId)], time);
|
||||
int time = p.getTimeInt() - r->getStartTime();
|
||||
int teamTotalTime = time + (r->tInTeam ? r->tInTeam->getTotalRunningTimeAtLegStart(r->tLeg, false) : 0);
|
||||
r->tOnCourseResults.emplace_back(ccId, courseCCid2CourseIx[make_pair(crs, ccId)], time, teamTotalTime);
|
||||
int clsId = r->getClassId(true);
|
||||
int leg = r->getLegNumber();
|
||||
if (cls->getQualificationFinal())
|
||||
@ -1072,6 +1073,8 @@ void oEvent::computePreliminarySplitResults(const set<int> &classes) const {
|
||||
|
||||
const set<int> &expectedCCid = classLeg2ExistingCCId[make_pair(clsId, leg)];
|
||||
size_t nRT = 0;
|
||||
int teamTotalOff = r.tInTeam ? r.tInTeam->getTotalRunningTimeAtLegStart(r.tLeg, false) : 0;
|
||||
|
||||
for (auto &radioTimes : r.tOnCourseResults.res) {
|
||||
if (expectedCCid.count(radioTimes.courseControlId))
|
||||
nRT++;
|
||||
@ -1091,8 +1094,9 @@ void oEvent::computePreliminarySplitResults(const set<int> &classes) const {
|
||||
}
|
||||
}
|
||||
if (!added) {
|
||||
int time = p.getTimeInt() - r.getStartTime(); //XXX Team time
|
||||
r.tOnCourseResults.emplace_back(ccId, p.tIndex, time);
|
||||
int time = p.getTimeInt() - r.getStartTime();
|
||||
int teamTotalTime = time + teamTotalOff;
|
||||
r.tOnCourseResults.emplace_back(ccId, p.tIndex, time, teamTotalTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1101,11 +1105,13 @@ void oEvent::computePreliminarySplitResults(const set<int> &classes) const {
|
||||
}
|
||||
|
||||
vector<tuple<int, int, int>> timeRunnerIx;
|
||||
vector<tuple<int, int, int>> totalTimeRunnerIx;
|
||||
|
||||
for (auto rList : runnerByClassLeg) {
|
||||
auto &rr = rList.second;
|
||||
pClass cls = getClass(rList.first.first);
|
||||
assert(cls);
|
||||
bool totRes = cls->getNumStages() > 1;
|
||||
//bool totRes = cls->getNumStages() > 1;
|
||||
|
||||
set<int> &legCCId = classLeg2ExistingCCId[rList.first];
|
||||
legCCId.insert(oPunch::PunchFinish);
|
||||
@ -1113,18 +1119,17 @@ void oEvent::computePreliminarySplitResults(const set<int> &classes) const {
|
||||
// Leg with negative sign
|
||||
int negLeg = 0;
|
||||
timeRunnerIx.clear();
|
||||
totalTimeRunnerIx.clear();
|
||||
|
||||
int nRun = rr.size();
|
||||
if (ccId == oPunch::PunchFinish) {
|
||||
negLeg = -1000; //Finish, smallest number
|
||||
for (int j = 0; j < nRun; j++) {
|
||||
auto r = rr[j];
|
||||
if (r->prelStatusOK(true, false, false)) {
|
||||
int time;
|
||||
if (!r->tInTeam || !totRes)
|
||||
time = r->getRunningTime(true);
|
||||
else {
|
||||
time = r->tInTeam->getLegRunningTime(r->tLeg, true, false);
|
||||
}
|
||||
int time = r->getRunningTime(true);
|
||||
int teamTotalTime = r->tInTeam ? r->tInTeam->getLegRunningTime(r->tLeg, true, false) : time;
|
||||
|
||||
int ix = -1;
|
||||
int nr = r->tOnCourseResults.res.size();
|
||||
for (int i = 0; i < nr; i++) {
|
||||
@ -1139,9 +1144,10 @@ void oEvent::computePreliminarySplitResults(const set<int> &classes) const {
|
||||
pCourse crs = r->getCourse(false);
|
||||
if (crs)
|
||||
nc = crs->getNumControls();
|
||||
r->tOnCourseResults.emplace_back(ccId, nc, time);
|
||||
r->tOnCourseResults.emplace_back(ccId, nc, time, teamTotalTime);
|
||||
}
|
||||
timeRunnerIx.emplace_back(time, j, ix);
|
||||
totalTimeRunnerIx.emplace_back(teamTotalTime, j, ix);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1152,37 +1158,51 @@ void oEvent::computePreliminarySplitResults(const set<int> &classes) const {
|
||||
for (int i = 0; i < nr; i++) {
|
||||
if (r->tOnCourseResults.res[i].courseControlId == ccId) {
|
||||
timeRunnerIx.emplace_back(r->tOnCourseResults.res[i].time, j, i);
|
||||
totalTimeRunnerIx.emplace_back(r->tOnCourseResults.res[i].teamTotalTime, j, i);
|
||||
|
||||
negLeg = min(negLeg, -r->tOnCourseResults.res[i].controlIx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sort(timeRunnerIx.begin(), timeRunnerIx.end());
|
||||
|
||||
auto computeResult = [&rr, &negLeg](vector<tuple<int, int, int>>& timeRunnerIx, bool total) {
|
||||
sort(timeRunnerIx.begin(), timeRunnerIx.end());
|
||||
|
||||
int place = 0;
|
||||
int time = 0;
|
||||
int leadTime = 0;
|
||||
int numPlace = timeRunnerIx.size();
|
||||
for (int i = 0; i < numPlace; i++) {
|
||||
int ct = get<0>(timeRunnerIx[i]);
|
||||
if (time != ct) {
|
||||
time = ct;
|
||||
place = i + 1;
|
||||
if (leadTime == 0)
|
||||
leadTime = time;
|
||||
}
|
||||
auto r = rr[get<1>(timeRunnerIx[i])];
|
||||
int locIx = get<2>(timeRunnerIx[i]);
|
||||
r->tOnCourseResults.res[locIx].place = place;
|
||||
r->tOnCourseResults.res[locIx].after = time - leadTime;
|
||||
int place = 0;
|
||||
int time = 0;
|
||||
int leadTime = 0;
|
||||
int numPlace = timeRunnerIx.size();
|
||||
for (int i = 0; i < numPlace; i++) {
|
||||
int ct = get<0>(timeRunnerIx[i]);
|
||||
if (time != ct) {
|
||||
time = ct;
|
||||
place = i + 1;
|
||||
if (leadTime == 0)
|
||||
leadTime = time;
|
||||
}
|
||||
auto r = rr[get<1>(timeRunnerIx[i])];
|
||||
int locIx = get<2>(timeRunnerIx[i]);
|
||||
if (total) {
|
||||
r->tOnCourseResults.res[locIx].teamTotalPlace = place;
|
||||
r->tOnCourseResults.res[locIx].teamTotalAfter = time - leadTime;
|
||||
}
|
||||
else {
|
||||
r->tOnCourseResults.res[locIx].place = place;
|
||||
r->tOnCourseResults.res[locIx].after = time - leadTime;
|
||||
|
||||
int &legWithTimeIndexNeg = r->currentControlTime.first;
|
||||
if (negLeg < legWithTimeIndexNeg) {
|
||||
legWithTimeIndexNeg = negLeg;
|
||||
r->currentControlTime.second = ct;
|
||||
int& legWithTimeIndexNeg = r->currentControlTime.first;
|
||||
if (negLeg < legWithTimeIndexNeg) {
|
||||
legWithTimeIndexNeg = negLeg;
|
||||
r->currentControlTime.second = ct;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
computeResult(timeRunnerIx, false);
|
||||
computeResult(totalTimeRunnerIx, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -331,7 +331,8 @@ int oListInfo::getMaxCharWidth(const oEvent *oe,
|
||||
break;
|
||||
case lPunchName:
|
||||
case lControlName:
|
||||
case lPunchNamedTime: {
|
||||
case lPunchNamedTime:
|
||||
case lPunchTeamTotalNamedTime: {
|
||||
wstring maxcn = lang.tl("Mål");
|
||||
vector<pControl> ctrl;
|
||||
oe->getControls(ctrl, false);
|
||||
@ -342,6 +343,8 @@ int oListInfo::getMaxCharWidth(const oEvent *oe,
|
||||
}
|
||||
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);
|
||||
}
|
||||
@ -366,6 +369,7 @@ int oListInfo::getMaxCharWidth(const oEvent *oe,
|
||||
case lRunnerTimeAdjustment:
|
||||
case lRunnerGeneralTimeAfter:
|
||||
case lPunchTotalTimeAfter:
|
||||
case lPunchTeamTotalTimeAfter:
|
||||
extra = L"+10:00";
|
||||
break;
|
||||
case lTeamRogainingPointOvertime:
|
||||
@ -390,12 +394,15 @@ int oListInfo::getMaxCharWidth(const oEvent *oe,
|
||||
case lRunnerStageStatus:
|
||||
case lRunnerTimePlaceFixed:
|
||||
case lPunchLostTime:
|
||||
case lPunchTotalTime:
|
||||
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)";
|
||||
@ -415,6 +422,7 @@ int oListInfo::getMaxCharWidth(const oEvent *oe,
|
||||
case lTeamTotalPlace:
|
||||
case lPunchControlPlace:
|
||||
case lPunchControlPlaceAcc:
|
||||
case lPunchControlPlaceTeamAcc:
|
||||
case lRunnerStagePlace:
|
||||
extra = L"99.";
|
||||
break;
|
||||
@ -517,7 +525,7 @@ int oListInfo::getMaxCharWidth(const oEvent *oe,
|
||||
pp.linearLegIndex = true;
|
||||
int numIter = 1;
|
||||
|
||||
if (pp.type == lPunchNamedTime || pp.type == lPunchTime) {
|
||||
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;
|
||||
@ -693,14 +701,16 @@ const wstring &oEvent::formatPunchStringAux(const oPrintPost &pp, const oListPar
|
||||
}
|
||||
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) {
|
||||
@ -710,9 +720,14 @@ const wstring &oEvent::formatPunchStringAux(const oPrintPost &pp, const oListPar
|
||||
break;
|
||||
}
|
||||
switch (pp.type) {
|
||||
case lPunchTime: {
|
||||
case lPunchTime:
|
||||
case lPunchTeamTime: {
|
||||
if (punch->hasTime()) {
|
||||
swprintf_s(bfw, L"\u2013 (%s)", formatTime(punch->getTimeInt() - r->getStartTime()).c_str());
|
||||
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"- (-)");
|
||||
@ -733,12 +748,24 @@ const wstring &oEvent::formatPunchStringAux(const oPrintPost &pp, const oListPar
|
||||
}
|
||||
case lPunchAbsTime: {
|
||||
if (punch->hasTime())
|
||||
wsptr = &getAbsTime(punch->getTimeInt());
|
||||
wsptr = &getAbsTime(punch->getTimeInt(), SubSecond::Off);
|
||||
break;
|
||||
}
|
||||
case lPunchTotalTime: {
|
||||
if (punch->hasTime())
|
||||
wsptr = &formatTime(punch->getTimeInt() - r->getStartTime());
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -865,6 +892,11 @@ const wstring &oEvent::formatSpecialStringAux(const oPrintPost &pp, const oListP
|
||||
}
|
||||
break;
|
||||
|
||||
case lCourseNumControls:
|
||||
if (pc)
|
||||
wsptr = &itow(pc->getNumControls());
|
||||
break;
|
||||
|
||||
case lCourseClasses:
|
||||
if (pc) {
|
||||
vector<pClass> cls;
|
||||
@ -1175,11 +1207,21 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
|
||||
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();
|
||||
@ -1783,7 +1825,7 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
|
||||
case lRunnerTimePlaceFixed:
|
||||
if (r && !invalidClass) {
|
||||
int t = r->getTimeWhenPlaceFixed();
|
||||
if (t == 0 || (t>0 && t < getComputerTime())) {
|
||||
if (t == 0 || (t > 0 && t < getComputerTime())) {
|
||||
wcscpy_s(wbf, lang.tl("klar").c_str());
|
||||
}
|
||||
else if (t == -1)
|
||||
@ -2259,17 +2301,22 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
|
||||
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;
|
||||
@ -2281,22 +2328,23 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
|
||||
}
|
||||
switch (pp.type) {
|
||||
case lPunchNamedSplit:
|
||||
if (ctrl && ctrl->hasName() && r->getPunchTime(counter.level3, false, true) > 0) {
|
||||
swprintf_s(wbf, L"%s", r->getNamedSplitS(counter.level3).c_str());
|
||||
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:
|
||||
if (ctrl && ctrl->hasName() && (!par.lineBreakControlList || r->getPunchTime(counter.level3, false, true) > 0)) {
|
||||
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->getNamedSplitS(counter.level3).c_str(),
|
||||
r->getPunchTimeS(counter.level3, false, true, SubSecond::Off).c_str());
|
||||
r->getNamedSplitS(counter.level3, SubSecond::Off).c_str(),
|
||||
r->getPunchTimeS(counter.level3, false, true, pp.type == lPunchTeamTotalNamedTime, SubSecond::Off).c_str());
|
||||
}
|
||||
break;
|
||||
|
||||
case lControlName:
|
||||
case lPunchName:
|
||||
if (ctrl && ctrl->hasName() && (!par.lineBreakControlList || r->getPunchTime(counter.level3, false, true) > 0)) {
|
||||
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) {
|
||||
@ -2304,27 +2352,30 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
|
||||
}
|
||||
break;
|
||||
|
||||
case lPunchTime: {
|
||||
case lPunchTime:
|
||||
case lPunchTeamTime: {
|
||||
swprintf_s(wbf, L"%s (%s)",
|
||||
r->getSplitTimeS(counter.level3, false).c_str(),
|
||||
r->getPunchTimeS(counter.level3, false, true, SubSecond::Off).c_str());
|
||||
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).c_str());
|
||||
wcscpy_s(wbf, r->getSplitTimeS(counter.level3, false, SubSecond::Off).c_str());
|
||||
break;
|
||||
}
|
||||
case lPunchTotalTime: {
|
||||
if (r->getPunchTime(counter.level3, false, true) > 0) {
|
||||
wcscpy_s(wbf, r->getPunchTimeS(counter.level3, false, true, SubSecond::Off).c_str());
|
||||
}
|
||||
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: {
|
||||
if (r->getPunchTime(counter.level3, false, true) > 0) {
|
||||
int rt = r->getLegTimeAfterAcc(counter.level3);
|
||||
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)).c_str());
|
||||
wcscpy_s(wbf, (L"+" + formatTime(rt, SubSecond::Off)).c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2350,8 +2401,9 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
|
||||
swprintf_s(wbf, L"%d", p);
|
||||
break;
|
||||
}
|
||||
case lPunchControlPlaceAcc: {
|
||||
int p = r->getLegPlaceAcc(counter.level3);
|
||||
case lPunchControlPlaceAcc:
|
||||
case lPunchControlPlaceTeamAcc: {
|
||||
int p = r->getLegPlaceAcc(counter.level3, pp.type == lPunchControlPlaceTeamAcc);
|
||||
if (p > 0)
|
||||
swprintf_s(wbf, L"%d", p);
|
||||
break;
|
||||
@ -2361,7 +2413,7 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
|
||||
break;
|
||||
}
|
||||
case lPunchAbsTime: {
|
||||
int t = r->getPunchTime(counter.level3, false, true);
|
||||
int t = r->getPunchTime(counter.level3, false, true, false);
|
||||
if (t > 0)
|
||||
wsptr = &getAbsTime(r->tStartTime + t);
|
||||
break;
|
||||
@ -3359,8 +3411,8 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
|
||||
}
|
||||
}
|
||||
else if (li.listSubType == li.EBaseTypeCoursePunches ||
|
||||
li.listSubType == li.EBaseTypeAllPunches) {
|
||||
pRunner r = it->Runners.empty() ? 0 : it->Runners[0];
|
||||
li.listSubType == li.EBaseTypeAllPunches) {
|
||||
pRunner r = it->getRunner(linearLegSpec);
|
||||
if (!r)
|
||||
return true;
|
||||
|
||||
|
||||
@ -61,6 +61,7 @@ enum EPostType {
|
||||
lCourseUsage,
|
||||
lCourseUsageNoVacant,
|
||||
lCourseClasses,
|
||||
lCourseNumControls,
|
||||
lRunnerName,
|
||||
lRunnerGivenName,
|
||||
lRunnerFamilyName,
|
||||
@ -172,19 +173,28 @@ enum EPostType {
|
||||
lTeamPlaceDiff,
|
||||
|
||||
lPunchNamedTime,
|
||||
lPunchTeamTotalNamedTime,
|
||||
lPunchNamedSplit,
|
||||
|
||||
lPunchName,
|
||||
|
||||
lPunchTime,
|
||||
lPunchTeamTime,
|
||||
|
||||
lPunchControlNumber,
|
||||
lPunchControlCode,
|
||||
lPunchLostTime,
|
||||
lPunchControlPlace,
|
||||
lPunchControlPlaceAcc,
|
||||
lPunchControlPlaceTeamAcc,
|
||||
|
||||
lPunchSplitTime,
|
||||
lPunchTotalTime,
|
||||
lPunchTotalTimeAfter,
|
||||
|
||||
lPunchTeamTotalTime,
|
||||
lPunchTeamTotalTimeAfter,
|
||||
|
||||
lPunchAbsTime,
|
||||
lPunchTimeSinceLast,
|
||||
|
||||
|
||||
141
code/oRunner.cpp
141
code/oRunner.cpp
@ -2027,19 +2027,9 @@ bool oRunner::operator<(const oRunner &c) const {
|
||||
pClub cl = getClubRef();
|
||||
pClub ocl = c.getClubRef();
|
||||
if (cl != ocl) {
|
||||
if (cl == nullptr && ocl)
|
||||
return true;
|
||||
else if (ocl == nullptr)
|
||||
return false;
|
||||
|
||||
const wstring a = cl->getName();
|
||||
const wstring b = ocl->getName();
|
||||
int res = CompareString(LOCALE_USER_DEFAULT, 0,
|
||||
a.c_str(), a.length(),
|
||||
b.c_str(), b.length());
|
||||
|
||||
if (res != CSTR_EQUAL)
|
||||
return res == CSTR_LESS_THAN;
|
||||
int cres = compareClubs(cl, ocl);
|
||||
if (cres != 2)
|
||||
return cres != 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2401,7 +2391,9 @@ bool oRunner::operator<(const oRunner &c) const {
|
||||
else return tStartTime < c.tStartTime;
|
||||
}
|
||||
else if (Club != c.Club) {
|
||||
return getClub() < c.getClub();
|
||||
int cres = compareClubs(Club, c.Club);
|
||||
if (cres != 2)
|
||||
return cres != 0;
|
||||
}
|
||||
}
|
||||
else if (oe->CurrentSortOrder == ClassTeamLeg) {
|
||||
@ -4173,11 +4165,11 @@ int oRunner::getSplitTime(int controlNumber, bool normalized) const
|
||||
{
|
||||
if (!Card) {
|
||||
if (controlNumber == 0)
|
||||
return getPunchTime(0, false, true);
|
||||
return getPunchTime(0, false, true, false);
|
||||
else {
|
||||
int ct = getPunchTime(controlNumber, false, true);
|
||||
int ct = getPunchTime(controlNumber, false, true, false);
|
||||
if (ct > 0) {
|
||||
int dt = getPunchTime(controlNumber - 1, false, true);
|
||||
int dt = getPunchTime(controlNumber - 1, false, true, false);
|
||||
if (dt > 0 && ct > dt)
|
||||
return ct - dt;
|
||||
}
|
||||
@ -4219,7 +4211,7 @@ int oRunner::getNamedSplit(int controlNumber) const {
|
||||
return -1;
|
||||
|
||||
int k=controlNumber-1;
|
||||
int ct = getPunchTime(controlNumber, false, true);
|
||||
int ct = getPunchTime(controlNumber, false, true, false);
|
||||
if (ct <= 0)
|
||||
return -1;
|
||||
|
||||
@ -4228,7 +4220,7 @@ int oRunner::getNamedSplit(int controlNumber) const {
|
||||
pControl c = crs->Controls[k];
|
||||
|
||||
if (c && c->hasName()) {
|
||||
int dt = getPunchTime(k, false, true);
|
||||
int dt = getPunchTime(k, false, true, false);
|
||||
if (dt > 0 && ct > dt)
|
||||
return max(ct - dt, -1);
|
||||
else return -1;
|
||||
@ -4240,52 +4232,53 @@ int oRunner::getNamedSplit(int controlNumber) const {
|
||||
return ct;
|
||||
}
|
||||
|
||||
wstring oRunner::getSplitTimeS(int controlNumber, bool normalized) const
|
||||
const wstring &oRunner::getSplitTimeS(int controlNumber, bool normalized, SubSecond mode) const
|
||||
{
|
||||
return formatTime(getSplitTime(controlNumber, normalized));
|
||||
return formatTime(getSplitTime(controlNumber, normalized), mode);
|
||||
}
|
||||
|
||||
wstring oRunner::getNamedSplitS(int controlNumber) const
|
||||
const wstring &oRunner::getNamedSplitS(int controlNumber, SubSecond mode) const
|
||||
{
|
||||
return formatTime(getNamedSplit(controlNumber));
|
||||
return formatTime(getNamedSplit(controlNumber), mode);
|
||||
}
|
||||
|
||||
int oRunner::getPunchTime(int controlNumber, bool normalized, bool adjusted) const
|
||||
int oRunner::getPunchTime(int controlIndex, bool normalized, bool adjusted, bool teamTotal) const
|
||||
{
|
||||
int off = teamTotal && tInTeam ? tInTeam->getTotalRunningTimeAtLegStart(getLegNumber(), false) : 0;
|
||||
|
||||
if (!Card) {
|
||||
pCourse pc = getCourse(false);
|
||||
if (!pc || controlNumber > pc->getNumControls())
|
||||
if (!pc || controlIndex > pc->getNumControls())
|
||||
return -1;
|
||||
|
||||
if (controlNumber == pc->getNumControls())
|
||||
return getFinishTime() - tStartTime;
|
||||
if (controlIndex == pc->getNumControls())
|
||||
return getFinishTime() - tStartTime + off;
|
||||
|
||||
int ccId = pc->getCourseControlId(controlNumber);
|
||||
int ccId = pc->getCourseControlId(controlIndex);
|
||||
pFreePunch fp = oe->getPunch(Id, ccId, getCardNo());
|
||||
if (fp)
|
||||
return fp->getTimeInt() - tStartTime;
|
||||
return fp->getTimeInt() - tStartTime + off;
|
||||
return -1;
|
||||
}
|
||||
const vector<SplitData> &st = getSplitTimes(normalized);
|
||||
|
||||
if (unsigned(controlNumber) < st.size()) {
|
||||
if (st[controlNumber].hasTime())
|
||||
return st[controlNumber].getTime(adjusted) - tStartTime;
|
||||
if (unsigned(controlIndex) < st.size()) {
|
||||
if (st[controlIndex].hasTime())
|
||||
return st[controlIndex].getTime(adjusted) - tStartTime + off;
|
||||
else return -1;
|
||||
}
|
||||
else if (unsigned(controlNumber) == st.size())
|
||||
return FinishTime - tStartTime;
|
||||
else if (unsigned(controlIndex) == st.size())
|
||||
return FinishTime - tStartTime + off;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
wstring oRunner::getPunchTimeS(int controlNumber, bool normalized, bool adjusted, SubSecond mode) const
|
||||
{
|
||||
return formatTime(getPunchTime(controlNumber, normalized, adjusted), mode);
|
||||
const wstring &oRunner::getPunchTimeS(int controlIndex, bool normalized, bool adjusted,
|
||||
bool teamTotal, SubSecond mode) const {
|
||||
return formatTime(getPunchTime(controlIndex, normalized, adjusted, teamTotal), mode);
|
||||
}
|
||||
|
||||
bool oAbstractRunner::isVacant() const
|
||||
{
|
||||
bool oAbstractRunner::isVacant() const {
|
||||
int vacClub = oe->getVacantClubIfExist(false);
|
||||
return vacClub > 0 && getClubId()==vacClub;
|
||||
}
|
||||
@ -4409,7 +4402,8 @@ void oRunner::fillSpeakerObject(int leg, int courseControlId, int previousContro
|
||||
}
|
||||
}
|
||||
|
||||
pRunner oEvent::findRunner(const wstring &s, int lastId, const unordered_set<int> &inputFilter,
|
||||
pRunner oEvent::findRunner(const wstring &s, int lastId,
|
||||
const unordered_set<int> &inputFilter,
|
||||
unordered_set<int> &matchFilter) const
|
||||
{
|
||||
matchFilter.clear();
|
||||
@ -4417,8 +4411,8 @@ pRunner oEvent::findRunner(const wstring &s, int lastId, const unordered_set<int
|
||||
int len = trm.length();
|
||||
int sn = _wtoi(trm.c_str());
|
||||
wchar_t s_lc[1024];
|
||||
wcscpy_s(s_lc, s.c_str());
|
||||
CharLowerBuff(s_lc, len);
|
||||
wcscpy_s(s_lc, s.c_str());
|
||||
prepareMatchString(s_lc, len);
|
||||
int score;
|
||||
pRunner res = 0;
|
||||
|
||||
@ -4929,7 +4923,7 @@ void oRunner::printSplits(gdioutput& gdi, const oListInfo* li) const {
|
||||
if (pc) {
|
||||
for (int n = 0; n < pc->nControls; n++) {
|
||||
spMax = max(spMax, getSplitTime(n, false));
|
||||
totMax = max(totMax, getPunchTime(n, false, false));
|
||||
totMax = max(totMax, getPunchTime(n, false, false, false));
|
||||
}
|
||||
}
|
||||
bool moreThanHour = max(totMax, getRunningTime(true)) >= timeConstHour;
|
||||
@ -5082,7 +5076,7 @@ void oRunner::printSplits(gdioutput& gdi, const oListInfo* li) const {
|
||||
adjust = getTimeAdjust(controlLegIndex);
|
||||
sp = getSplitTime(controlLegIndex, false);
|
||||
if (sp > 0) {
|
||||
punchTime = getPunchTimeS(controlLegIndex, false, false, SubSecond::Off);
|
||||
punchTime = getPunchTimeS(controlLegIndex, false, false, false, SubSecond::Off);
|
||||
gdi.addStringUT(cy, cx + c2, fontSmall | textRight, formatTime(sp, SubSecond::Off));
|
||||
}
|
||||
}
|
||||
@ -5807,7 +5801,7 @@ void oRunner::getLegTimeAfter(vector<int> ×) const
|
||||
}
|
||||
}
|
||||
|
||||
void oRunner::getLegTimeAfterAcc(vector<int> ×) const
|
||||
void oRunner::getLegTimeAfterAcc(vector<ResultData> ×) const
|
||||
{
|
||||
times.clear();
|
||||
if (splitTimes.empty() || !Class || tStartTime<=0)
|
||||
@ -5835,6 +5829,9 @@ void oRunner::getLegTimeAfterAcc(vector<int> ×) const
|
||||
//xxx reorder output
|
||||
times.resize(nc+1);
|
||||
|
||||
bool isRelayTeam = tInTeam != nullptr;
|
||||
int off = tInTeam ? tInTeam->getTotalRunningTimeAtLegStart(tLeg, false) : 0;
|
||||
|
||||
for (unsigned k = 0; k<=nc; k++) {
|
||||
int s = 0;
|
||||
if (k < sp.size())
|
||||
@ -5843,18 +5840,27 @@ void oRunner::getLegTimeAfterAcc(vector<int> ×) const
|
||||
s = FinishTime;
|
||||
|
||||
if (s>0) {
|
||||
times[k] = s - tStartTime - leaders[k];
|
||||
if (times[k]<0)
|
||||
times[k] = -1;
|
||||
times[k].data = s - tStartTime - leaders[k];
|
||||
if (times[k].data < 0)
|
||||
times[k].data = -1;
|
||||
}
|
||||
else
|
||||
times[k] = -1;
|
||||
times[k].data = -1;
|
||||
|
||||
if (!isRelayTeam || times[k].data < 0)
|
||||
times[k].teamTotalData = times[k].data;
|
||||
else {
|
||||
if (k < nc)
|
||||
times[k].teamTotalData = s - tStartTime + off - cls->getAccLegControlLeader(tLeg, pc->getCourseControlId(k));
|
||||
else
|
||||
times[k].teamTotalData = s - tStartTime + off - cls->getAccLegControlLeader(tLeg, oPunch::PunchFinish);
|
||||
}
|
||||
}
|
||||
|
||||
// Normalized order
|
||||
const vector<int> &reorder = getCourse(true)->getMapToOriginalOrder();
|
||||
if (!reorder.empty()) {
|
||||
vector<int> orderedTimes(times.size());
|
||||
vector<ResultData> orderedTimes(times.size());
|
||||
for (size_t k = 0; k < min(reorder.size(), times.size()); k++) {
|
||||
orderedTimes[k] = times[reorder[k]];
|
||||
}
|
||||
@ -5862,7 +5868,7 @@ void oRunner::getLegTimeAfterAcc(vector<int> ×) const
|
||||
}
|
||||
}
|
||||
|
||||
void oRunner::getLegPlacesAcc(vector<int> &places) const
|
||||
void oRunner::getLegPlacesAcc(vector<ResultData> &places) const
|
||||
{
|
||||
places.clear();
|
||||
pCourse pc = getCourse(false);
|
||||
@ -5880,6 +5886,10 @@ void oRunner::getLegPlacesAcc(vector<int> &places) const
|
||||
const unsigned nc = pc->getNumControls();
|
||||
const vector<SplitData> &sp = getSplitTimes(true);
|
||||
places.resize(nc+1);
|
||||
|
||||
bool isRelayTeam = tInTeam != nullptr;
|
||||
int off = tInTeam ? tInTeam->getTotalRunningTimeAtLegStart(tLeg, false) : 0;
|
||||
|
||||
for (unsigned k = 0; k<=nc; k++) {
|
||||
int s = 0;
|
||||
if (k < sp.size())
|
||||
@ -5890,17 +5900,24 @@ void oRunner::getLegPlacesAcc(vector<int> &places) const
|
||||
if (s>0) {
|
||||
int time = s - tStartTime;
|
||||
|
||||
if (time>0)
|
||||
places[k] = cls->getAccLegPlace(id, k, time);
|
||||
else
|
||||
places[k] = 0;
|
||||
if (time > 0) {
|
||||
places[k].data = cls->getAccLegPlace(id, k, time);
|
||||
if (k < nc)
|
||||
places[k].teamTotalData = cls->getAccLegControlPlace(tLeg, pc->getCourseControlId(k), time + off);
|
||||
else
|
||||
places[k].teamTotalData = cls->getAccLegControlPlace(tLeg, oPunch::PunchFinish, time + off);
|
||||
}
|
||||
else {
|
||||
places[k].data = 0;
|
||||
places[k].teamTotalData = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Normalized order
|
||||
const vector<int> &reorder = getCourse(true)->getMapToOriginalOrder();
|
||||
if (!reorder.empty()) {
|
||||
vector<int> orderedPlaces(reorder.size());
|
||||
vector<ResultData> orderedPlaces(reorder.size());
|
||||
for (size_t k = 0; k < reorder.size(); k++) {
|
||||
orderedPlaces[k] = places[reorder[k]];
|
||||
}
|
||||
@ -5974,31 +5991,31 @@ int oRunner::getLegTimeAfter(int ctrlNo) const {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int oRunner::getLegPlaceAcc(int ctrlNo) const {
|
||||
int oRunner::getLegPlaceAcc(int ctrlNo, bool teamTotal) const {
|
||||
for (auto &res : tOnCourseResults.res) {
|
||||
if (res.controlIx == ctrlNo)
|
||||
return res.place;
|
||||
return teamTotal ? res.place : res.teamTotalPlace;
|
||||
}
|
||||
if (!Card) {
|
||||
return 0;
|
||||
}
|
||||
setupRunnerStatistics();
|
||||
if (unsigned(ctrlNo) < tPlaceLegAcc.size())
|
||||
return tPlaceLegAcc[ctrlNo];
|
||||
return tPlaceLegAcc[ctrlNo].get(teamTotal);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int oRunner::getLegTimeAfterAcc(int ctrlNo) const {
|
||||
int oRunner::getLegTimeAfterAcc(int ctrlNo, bool teamTotal) const {
|
||||
for (auto &res : tOnCourseResults.res) {
|
||||
if (res.controlIx == ctrlNo)
|
||||
return res.after;
|
||||
return teamTotal ? res.teamTotalAfter : res.after;
|
||||
}
|
||||
if (!Card)
|
||||
return -1;
|
||||
setupRunnerStatistics();
|
||||
if (unsigned(ctrlNo) < tAfterLegAcc.size())
|
||||
return tAfterLegAcc[ctrlNo];
|
||||
return tAfterLegAcc[ctrlNo].get(teamTotal);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -87,6 +87,25 @@ enum SortOrder {
|
||||
SortEnumLastItem
|
||||
};
|
||||
|
||||
static bool orderByClass(SortOrder so) {
|
||||
switch (so) {
|
||||
case ClassStartTime:
|
||||
case ClassTeamLeg:
|
||||
case ClassResult:
|
||||
case ClassDefaultResult:
|
||||
case ClassCourseResult:
|
||||
case ClassTotalResult:
|
||||
case ClassTeamLegResult:
|
||||
case ClassFinishTime:
|
||||
case ClassStartTimeClub:
|
||||
case ClassPoints:
|
||||
case ClassLiveResult:
|
||||
case ClassKnockoutTotalResult:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class oRunner;
|
||||
typedef oRunner* pRunner;
|
||||
typedef const oRunner* cRunner;
|
||||
@ -178,6 +197,9 @@ public:
|
||||
protected:
|
||||
TempResult tmpResult;
|
||||
|
||||
/** Return 1 if a<b, 0 if b<a, otherwise 2.*/
|
||||
static int compareClubs(const oClub* a, const oClub* b);
|
||||
|
||||
mutable int tTimeAdjustment;
|
||||
mutable int tPointAdjustment;
|
||||
mutable int tAdjustDataRevision;
|
||||
@ -551,6 +573,23 @@ public:
|
||||
};
|
||||
|
||||
class oRunner final: public oAbstractRunner {
|
||||
public:
|
||||
struct ResultData {
|
||||
private:
|
||||
int data = 0;
|
||||
int teamTotalData = 0;
|
||||
|
||||
public:
|
||||
ResultData(int data, int teamTotalData) : data(data), teamTotalData(teamTotalData) { }
|
||||
ResultData() = default;
|
||||
|
||||
int get(bool total) const {
|
||||
return total ? teamTotalData : data;
|
||||
}
|
||||
|
||||
friend class oRunner;
|
||||
};
|
||||
|
||||
protected:
|
||||
pCourse Course;
|
||||
|
||||
@ -633,24 +672,32 @@ protected:
|
||||
|
||||
void clearOnChangedRunningTime();
|
||||
|
||||
|
||||
// Cached runner statistics
|
||||
mutable vector<int> tMissedTime;
|
||||
mutable vector<int> tPlaceLeg;
|
||||
mutable vector<int> tAfterLeg;
|
||||
mutable vector<int> tPlaceLegAcc;
|
||||
mutable vector<int> tAfterLegAcc;
|
||||
mutable vector<ResultData> tPlaceLegAcc;
|
||||
mutable vector<ResultData> tAfterLegAcc;
|
||||
|
||||
// Used to calculate temporary split time results
|
||||
struct OnCourseResult {
|
||||
OnCourseResult(int courseControlId,
|
||||
int controlIx,
|
||||
int time) : courseControlId(courseControlId),
|
||||
controlIx(controlIx), time(time) {}
|
||||
int time,
|
||||
int teamTotalTime) : courseControlId(courseControlId),
|
||||
controlIx(controlIx), time(time),
|
||||
teamTotalTime(teamTotalTime) {}
|
||||
int courseControlId;
|
||||
int controlIx;
|
||||
int time;
|
||||
int place;
|
||||
int after;
|
||||
int teamTotalTime;
|
||||
|
||||
int place = -1;
|
||||
int after = -1;
|
||||
|
||||
int teamTotalPlace = -1;
|
||||
int teamTotalAfter = -1;
|
||||
};
|
||||
mutable pair<int, int> currentControlTime;
|
||||
|
||||
@ -660,8 +707,9 @@ protected:
|
||||
void clear() { hasAnyRes = false; res.clear(); }
|
||||
void emplace_back(int courseControlId,
|
||||
int controlIx,
|
||||
int time) {
|
||||
res.emplace_back(courseControlId, controlIx, time);
|
||||
int time,
|
||||
int teamTotalTime) {
|
||||
res.emplace_back(courseControlId, controlIx, time, teamTotalTime);
|
||||
hasAnyRes = true;
|
||||
}
|
||||
bool empty() const { return hasAnyRes == false; }
|
||||
@ -867,8 +915,8 @@ public:
|
||||
int getMissedTime(int ctrlNo) const;
|
||||
int getLegPlace(int ctrlNo) const;
|
||||
int getLegTimeAfter(int ctrlNo) const;
|
||||
int getLegPlaceAcc(int ctrlNo) const;
|
||||
int getLegTimeAfterAcc(int ctrlNo) const;
|
||||
int getLegPlaceAcc(int ctrlNo, bool teamTotal) const;
|
||||
int getLegTimeAfterAcc(int ctrlNo, bool teamTotal) const;
|
||||
|
||||
/** Calculate the time when the runners place is fixed, i.e,
|
||||
when no other runner can threaten the place.
|
||||
@ -957,22 +1005,25 @@ public:
|
||||
void getLegPlaces(vector<int> &places) const;
|
||||
void getLegTimeAfter(vector<int> &deltaTimes) const;
|
||||
|
||||
void getLegPlacesAcc(vector<int> &places) const;
|
||||
void getLegTimeAfterAcc(vector<int> &deltaTimes) const;
|
||||
void getLegPlacesAcc(vector<ResultData> &places) const;
|
||||
void getLegTimeAfterAcc(vector<ResultData> &deltaTimes) const;
|
||||
|
||||
// Normalized = true means permuted to the unlooped version of the course
|
||||
int getSplitTime(int controlNumber, bool normalized) const;
|
||||
int getTimeAdjust(int controlNumber) const;
|
||||
|
||||
int getNamedSplit(int controlNumber) const;
|
||||
wstring getNamedSplitS(int controlNumber) const;
|
||||
const wstring &getNamedSplitS(int controlNumber, SubSecond mode) const;
|
||||
|
||||
/** Get running time from start to a control (specified by its index on the course)
|
||||
normalized: true means permuted to the unlooped version of the course
|
||||
teamTotalTime: true means time is measured from the team's starting time
|
||||
*/
|
||||
int getPunchTime(int controlIndex, bool normalized, bool adjusted, bool teamTotalTime) const;
|
||||
const wstring &getPunchTimeS(int controlIndex, bool normalized, bool adjusted, bool teamTotalTime, SubSecond mode) const;
|
||||
|
||||
// Normalized = true means permuted to the unlooped version of the course
|
||||
int getPunchTime(int controlNumber, bool normalized, bool adjusted) const;
|
||||
wstring getPunchTimeS(int controlNumber, bool normalized, bool adjusted, SubSecond mode) const;
|
||||
|
||||
// Normalized = true means permuted to the unlooped version of the course
|
||||
wstring getSplitTimeS(int controlNumber, bool normalized) const;
|
||||
const wstring &getSplitTimeS(int controlNumber, bool normalized, SubSecond mode) const;
|
||||
|
||||
void addTableRow(Table &table) const;
|
||||
pair<int, bool> inputData(int id, const wstring &input,
|
||||
|
||||
@ -436,6 +436,17 @@ int oTeam::getLegFinishTime(int leg) const
|
||||
else return 0;
|
||||
}
|
||||
|
||||
int oTeam::getTotalRunningTimeAtLegStart(int leg, bool multidayTotal) const {
|
||||
int off = multidayTotal ? max(0, getInputTime()) : 0;
|
||||
if (!Class || leg == 0)
|
||||
return off;
|
||||
int pleg = Class->getPreceedingLeg(leg);
|
||||
if (pleg < 0)
|
||||
return off;
|
||||
|
||||
return getLegRunningTime(pleg, false, multidayTotal);
|
||||
}
|
||||
|
||||
int oTeam::getRunningTime(bool computedTime) const {
|
||||
return getLegRunningTime(-1, computedTime, false);
|
||||
}
|
||||
@ -812,9 +823,7 @@ wstring oTeam::getLegPrintPlaceS(int leg, bool multidayTotal, bool withDot) cons
|
||||
return _EmptyWString;
|
||||
}
|
||||
|
||||
bool oTeam::compareResultClub(const oTeam& a, const oTeam& b) {
|
||||
pClub ca = a.getClubRef();
|
||||
pClub cb = b.getClubRef();
|
||||
int oAbstractRunner::compareClubs(const oClub* ca, const oClub* cb) {
|
||||
if (ca != cb) {
|
||||
if (ca == nullptr && cb)
|
||||
return true;
|
||||
@ -830,6 +839,17 @@ bool oTeam::compareResultClub(const oTeam& a, const oTeam& b) {
|
||||
if (res != CSTR_EQUAL)
|
||||
return res == CSTR_LESS_THAN;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool oTeam::compareResultClub(const oTeam& a, const oTeam& b) {
|
||||
pClub ca = a.getClubRef();
|
||||
pClub cb = b.getClubRef();
|
||||
if (ca != cb) {
|
||||
int cres = compareClubs(ca, cb);
|
||||
if (cres != 2)
|
||||
return cres != 0;
|
||||
}
|
||||
return compareResult(a, b);
|
||||
}
|
||||
|
||||
@ -855,8 +875,13 @@ bool oTeam::compareResult(const oTeam &a, const oTeam &b)
|
||||
|
||||
int aix = a.getDCI().getInt("SortIndex");
|
||||
int bix = b.getDCI().getInt("SortIndex");
|
||||
if (aix != bix)
|
||||
if (aix != bix) {
|
||||
if (aix == 0)
|
||||
aix = numeric_limits<int>::max();
|
||||
if (bix == 0)
|
||||
bix = numeric_limits<int>::max();
|
||||
return aix < bix;
|
||||
}
|
||||
|
||||
return CompareString(LOCALE_USER_DEFAULT, 0,
|
||||
a.sName.c_str(), a.sName.length(),
|
||||
@ -877,6 +902,24 @@ bool oTeam::compareResultNoSno(const oTeam &a, const oTeam &b)
|
||||
else if (a.tmpSortTime != b.tmpSortTime)
|
||||
return a.tmpSortTime<b.tmpSortTime;
|
||||
|
||||
int aix = a.getDCI().getInt("SortIndex");
|
||||
int bix = b.getDCI().getInt("SortIndex");
|
||||
if (aix != bix) {
|
||||
if (aix == 0)
|
||||
aix = numeric_limits<int>::max();
|
||||
if (bix == 0)
|
||||
bix = numeric_limits<int>::max();
|
||||
return aix < bix;
|
||||
}
|
||||
|
||||
pClub ca = a.getClubRef();
|
||||
pClub cb = b.getClubRef();
|
||||
if (ca != cb) {
|
||||
int cres = compareClubs(ca, cb);
|
||||
if (cres != 2)
|
||||
return cres != 0;
|
||||
}
|
||||
|
||||
return CompareString(LOCALE_USER_DEFAULT, 0,
|
||||
a.sName.c_str(), a.sName.length(),
|
||||
b.sName.c_str(), b.sName.length()) == CSTR_LESS_THAN;
|
||||
@ -1751,7 +1794,7 @@ pRunner oTeam::getRunner(unsigned leg) const {
|
||||
if (leg==-1)
|
||||
leg=Runners.size()-1;
|
||||
|
||||
return leg<Runners.size() ? Runners[leg] : 0;
|
||||
return leg<Runners.size() ? Runners[leg] : nullptr;
|
||||
}
|
||||
|
||||
int oTeam::getRogainingPoints(bool computed, bool multidayTotal) const {
|
||||
|
||||
@ -268,7 +268,10 @@ public:
|
||||
wstring getLegRunningTimeS(int leg, bool computed, bool multidayTotal, SubSecond mode) const;
|
||||
|
||||
int getLegRunningTime(int leg, bool computed, bool multidayTotal) const;
|
||||
|
||||
|
||||
// Get the team's total running time when starting specified leg
|
||||
int getTotalRunningTimeAtLegStart(int leg, bool multidayTotal) const;
|
||||
|
||||
RunnerStatus getLegStatus(int leg, bool computed, bool multidayTotal) const;
|
||||
const wstring &getLegStatusS(int leg, bool computed, bool multidayTotal) const;
|
||||
|
||||
|
||||
@ -240,7 +240,7 @@ pTeam oEvent::findTeam(const wstring &s, int lastId, unordered_set<int> &filter)
|
||||
int len = trm.length();
|
||||
wchar_t s_lc[1024];
|
||||
wcscpy_s(s_lc, trm.c_str());
|
||||
CharLowerBuff(s_lc, len);
|
||||
prepareMatchString(s_lc, len);
|
||||
|
||||
int sn = _wtoi(s.c_str());
|
||||
oTeamList::const_iterator it;
|
||||
|
||||
@ -478,7 +478,7 @@ void OnlineInput::processEntries(oEvent &oe, const xmlList &entries) {
|
||||
bool paid = entry.getObjectBool("paid");
|
||||
|
||||
xmlobject xname = entry.getObject("name");
|
||||
wstring birthyear = 0;
|
||||
wstring birthyear;
|
||||
if (xname) {
|
||||
xname.getObjectString("birthyear", birthyear);
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
#define IDI_SPLASHIMAGE 512
|
||||
#define IDI_MEOSIMAGE 513
|
||||
#define IDI_MEOSINFO 514
|
||||
#define IDI_MEOSEDIT 515
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
|
||||
@ -1150,7 +1150,7 @@ void RestServer::lookup(oEvent &oe, const string &what, const multimap<string, s
|
||||
auto &sd = r->getSplitTimes(false);
|
||||
vector<int> after;
|
||||
r->getLegTimeAfter(after);
|
||||
vector<int> afterAcc;
|
||||
vector<oRunner::ResultData> afterAcc;
|
||||
r->getLegTimeAfterAcc(afterAcc);
|
||||
vector<int> delta;
|
||||
r->getSplitAnalysis(delta);
|
||||
@ -1177,8 +1177,8 @@ void RestServer::lookup(oEvent &oe, const string &what, const multimap<string, s
|
||||
else
|
||||
analysis[0].second = L"";
|
||||
|
||||
if (afterAcc[ix] > 0)
|
||||
analysis[1].second = formatTime(afterAcc[ix]);
|
||||
if (afterAcc[ix].get(0) > 0)
|
||||
analysis[1].second = formatTime(afterAcc[ix].get(false));
|
||||
else
|
||||
analysis[1].second = L"";
|
||||
|
||||
@ -1190,7 +1190,7 @@ void RestServer::lookup(oEvent &oe, const string &what, const multimap<string, s
|
||||
int place = r->getLegPlace(ix);
|
||||
analysis[3].second = place > 0 ? itow(place) : L"";
|
||||
|
||||
int placeAcc = r->getLegPlaceAcc(ix);
|
||||
int placeAcc = r->getLegPlaceAcc(ix, false);
|
||||
analysis[4].second = placeAcc > 0 ? itow(placeAcc) : L"";
|
||||
|
||||
xml.write("Analysis", analysis, L"");
|
||||
|
||||
@ -2683,3 +2683,8 @@ Bevara höjd/bredd-relationen = Bevara höjd/bredd-relationen
|
||||
RunnerLegTeamLeaderName = Först i mål på sträckan
|
||||
info:offsetclassid = Om du importerar anmälningar och klasser från olika källor till samma tävling kan det hända att klassernas Id-nummer krockar. För att hålla isär klasserna kan du då ange en förskjutning av Id-nummer när du arbetar med datafiler från en viss källa; denna kommer att adderas till klassernas Id-nummer.\n\nDu måste ange samma förskjutning varje gång du importerar från en viss källa. Ett lämpligt värde kan vara 1000 (som fungerar om all Id-nummer är mindre än 1000).
|
||||
Förskjutning av klassers Id = Förskjutning av klassers Id
|
||||
Tilldela nummerlapp till vakanter = Tilldela nummerlapp till vakanter
|
||||
Avläsning = Avläsning
|
||||
Inmatning Testning = Inmatning Testning
|
||||
Testning = Testning
|
||||
CourseNumControls = Antal kontroller
|
||||
|
||||
Loading…
Reference in New Issue
Block a user