// // Wizard.cpp - 対話式ウィザード & 目的テンプレート選択(CTaskDialog ベース、.rc 不要)。 // #include "stdafx.h" #include "Wizard.h" #include "core/Templates.h" #include "core/StepCatalog.h" using namespace core; namespace { // コマンドリンク付き質問を1つ出し、選ばれた ID を返す(キャンセル=0)。 struct Choice { int id; LPCWSTR caption; }; int AskChoices(CWnd* parent, LPCWSTR title, LPCWSTR main, LPCWSTR content, const Choice* choices, int n) { if (!CTaskDialog::IsSupported()) { AfxMessageBox(L"この環境ではウィザードを表示できません。"); return 0; } CTaskDialog dlg(content, main, title, TDCBF_CANCEL_BUTTON, TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION); for (int i = 0; i < n; i++) dlg.AddCommandControl(choices[i].id, choices[i].caption); INT_PTR r = dlg.DoModal(parent ? parent->GetSafeHwnd() : NULL); for (int i = 0; i < n; i++) if (r == choices[i].id) return choices[i].id; return 0; // キャンセル } // 検査ステップ(末尾想定)の min/max を書き換える。 void SetInspectRange(Recipe& rc, double lo, double hi) { for (auto it = rc.steps.rbegin(); it != rc.steps.rend(); ++it) { if (IsInspect(it->kind)) { it->SetParam(L"min", lo); it->SetParam(L"max", hi); return; } } } } // namespace bool wizard::ChooseTemplate(CWnd* parent, Recipe& out) { auto tps = AllTemplates(); std::vector ch; std::vector caps; caps.reserve(tps.size()); for (size_t i = 0; i < tps.size(); i++) { caps.push_back(tps[i].name + L"\n" + tps[i].desc); } for (size_t i = 0; i < tps.size(); i++) ch.push_back({ (int)(2001 + i), (LPCWSTR)caps[i] }); int r = AskChoices(parent, L"テンプレートから作る", L"検査の目的を選んでください", L"選ぶと、その目的に合った検査レシピが自動で入ります。あとでスライダーで微調整できます。", ch.data(), (int)ch.size()); if (r == 0) return false; int idx = r - 2001; if (idx < 0 || idx >= (int)tps.size()) return false; out = tps[idx].recipe; return true; } bool wizard::BuildWithWizard(CWnd* parent, Recipe& out) { // Q1: 何を検査? Choice q1[] = { { 1, L"キズ・汚れを見つける\n表面に傷や汚れが無いか調べます" }, { 2, L"欠け・穴の数を数える\n穴やパターンの数が想定どおりか調べます" }, { 3, L"明るさを確認する\n全体の明るさが基準内か調べます" }, { 4, L"文字・印字の有無を見る\n印字・マークがあるか(無いか)調べます" }, }; int a1 = AskChoices(parent, L"検査ウィザード (1/2)", L"何を検査したいですか?", L"目的に合わせて質問します。", q1, 4); if (a1 == 0) return false; auto tps = AllTemplates(); // [0]キズ [1]欠け [2]明るさ [3]文字 if (a1 == 1) // キズ・汚れ { out = tps[0].recipe; Choice q2[] = { { 10, L"厳しい:キズは1個も許さない(0個で合格)" }, { 11, L"ふつう:小さなキズ1個までは許容(1個まで合格)" }, { 12, L"ゆるい:3個まで許容(3個まで合格)" }, }; int a2 = AskChoices(parent, L"検査ウィザード (2/2)", L"どのくらい厳しく判定しますか?", L"許容するキズの数を選びます。", q2, 3); if (a2 == 0) return false; double mx = (a2 == 10) ? 0 : (a2 == 11) ? 1 : 3; SetInspectRange(out, 0, mx); return true; } if (a1 == 2) // 欠け・穴の数 { out = tps[1].recipe; Choice q2[] = { { 20, L"ちょうど1個なら合格" }, { 21, L"1〜2個なら合格" }, { 22, L"1〜4個なら合格" }, { 23, L"あとで自分で決める(1〜4個で仮設定)" }, }; int a2 = AskChoices(parent, L"検査ウィザード (2/2)", L"いくつなら合格にしますか?", L"想定される穴/塊の数を選びます。", q2, 4); if (a2 == 0) return false; double lo = 1, hi = 4; if (a2 == 20) { lo = 1; hi = 1; } else if (a2 == 21) { lo = 1; hi = 2; } else { lo = 1; hi = 4; } SetInspectRange(out, lo, hi); return true; } if (a1 == 3) // 明るさ { out = tps[2].recipe; Choice q2[] = { { 30, L"暗すぎ・明るすぎを弾く(80〜180)" }, { 31, L"明るめ重視(120〜220)" }, { 32, L"暗め重視(40〜140)" }, }; int a2 = AskChoices(parent, L"検査ウィザード (2/2)", L"どの明るさなら合格ですか?", L"合格とする平均の明るさの範囲を選びます。", q2, 3); if (a2 == 0) return false; if (a2 == 30) SetInspectRange(out, 80, 180); else if (a2 == 31) SetInspectRange(out, 120, 220); else SetInspectRange(out, 40, 140); return true; } // a1 == 4 文字・印字 { out = tps[3].recipe; Choice q2[] = { { 40, L"印字が「ある」ことを確認したい(あれば合格)" }, { 41, L"印字が「ない」ことを確認したい(無ければ合格)" }, }; int a2 = AskChoices(parent, L"検査ウィザード (2/2)", L"どちらを合格にしますか?", L"印字の有無どちらを合格とするか選びます。", q2, 2); if (a2 == 0) return false; if (a2 == 40) SetInspectRange(out, 2, 100); // 2%以上インクあり else SetInspectRange(out, 0, 1); // ほぼ無し return true; } }