PageRenderTime 138ms CodeModel.GetById 2ms app.highlight 124ms RepoModel.GetById 1ms app.codeStats 0ms

/cwxeditor_src/cwx/editor/gui/dwt/castcarddialog.d

https://bitbucket.org/k4nagatsuki/cwxeditor
D | 1467 lines | 1429 code | 35 blank | 3 comment | 150 complexity | c2109dab7a21c1543df97af3836e90bb MD5 | raw file
   1
   2module cwx.editor.gui.dwt.castcarddialog;
   3
   4import cwx.coupon;
   5import cwx.summary;
   6import cwx.card;
   7import cwx.types;
   8import cwx.features;
   9import cwx.utils;
  10import cwx.race;
  11import cwx.xml;
  12import cwx.skin;
  13import cwx.motion;
  14import cwx.path;
  15import cwx.menu;
  16import cwx.types;
  17import cwx.imagesize;
  18
  19import cwx.editor.gui.dwt.dprops;
  20import cwx.editor.gui.dwt.dskin;
  21import cwx.editor.gui.dwt.dutils;
  22import cwx.editor.gui.dwt.commons;
  23import cwx.editor.gui.dwt.materialselect;
  24import cwx.editor.gui.dwt.imageselect;
  25import cwx.editor.gui.dwt.customtext;
  26import cwx.editor.gui.dwt.customtable;
  27import cwx.editor.gui.dwt.centerlayout;
  28import cwx.editor.gui.dwt.radarspinner;
  29import cwx.editor.gui.dwt.xmlbytestransfer;
  30import cwx.editor.gui.dwt.absdialog;
  31import cwx.editor.gui.dwt.undo;
  32import cwx.editor.gui.dwt.dmenu;
  33import cwx.editor.gui.dwt.couponview;
  34import cwx.editor.gui.dwt.scales;
  35
  36import std.datetime;
  37import std.string;
  38import std.conv;
  39
  40import org.eclipse.swt.all;
  41
  42import java.lang.all;
  43
  44public:
  45
  46/// ???????????????????
  47class CastCardDialog : AbsDialog {
  48private:
  49	string _id;
  50
  51	int _readOnly = 0;
  52	Commons _comm;
  53	Props _prop;
  54	Summary _summ;
  55	CastCard _card;
  56
  57	ImageSelect!(MtType.CARD) _imgPath;
  58	FixedWidthText _desc;
  59	GBLimitText _name;
  60	Spinner _level;
  61	Spinner _lifeMax;
  62	CouponView!(CVType.Cast) _couponView;
  63	Combo _race;
  64	Button[Sex] _sex;
  65	Button _sexU;
  66	Button[Period] _period;
  67	Button _periodU;
  68	Composite _natureComp;
  69	Button[Nature] _nature;
  70	Button _natureU;
  71	bool _showSpNature = false;
  72	Button[Makings] _makings;
  73	Button _resW;
  74	Button _resM;
  75	Button _undead;
  76	Button _automaton;
  77	Button _unholy;
  78	Button _constructure;
  79	Button _res[Element];
  80	Button _weak[Element];
  81	int[Physical] _phyTbl;
  82	Composite _phyParent;
  83	RadarSpinner _phyR = null;
  84	Scales _phyS = null;
  85	Scale[Mental] _mtl;
  86	Label _sumPhy;
  87	int[Enhance] _enhTbl;
  88	Composite _enhParent;
  89	RadarSpinner _enhR = null;
  90	Scales _enhS = null;
  91
  92	Spinner _life;
  93	Button _lifeUseMax;
  94	Spinner[Enhance] _liveEnh;
  95	Spinner[Enhance] _enhRound;
  96	Spinner _paralyze;
  97	Spinner _poison;
  98	Spinner _bind;
  99	Spinner _silence;
 100	Spinner _faceUp;
 101	Spinner _antiMagic;
 102	Mentality[int] _mtlyTbl;
 103	Combo _mtly;
 104	Spinner _mtlyRound;
 105
 106	Skin _summSkin;
 107	@property
 108	Skin summSkin() { mixin(S_TRACE);
 109		return _summSkin ? _summSkin : _comm.skin;
 110	}
 111
 112	void refreshWarning() { mixin(S_TRACE);
 113		string[] ws;
 114		if (_name.over) { mixin(S_TRACE);
 115			ws ~= .tryFormat(_prop.msgs.warningNameLenOver, _prop.looks.castNameLimit, _prop.looks.castNameLimit / 2);
 116		}
 117		ws ~= _imgPath.warnings;
 118
 119		warning = ws;
 120	}
 121
 122	@property
 123	Race selectedRace() { mixin(S_TRACE);
 124		if (_race) { mixin(S_TRACE);
 125			int index = _race.getSelectionIndex();
 126			if (index > 0) { mixin(S_TRACE);
 127				return summSkin.races[index - 1];
 128			}
 129		}
 130		return null;
 131	}
 132	void raceToolTip() { mixin(S_TRACE);
 133		if (_race) { mixin(S_TRACE);
 134			auto race = selectedRace;
 135			_race.setToolTipText(race ? race.desc : "");
 136		}
 137	}
 138	class SelectRace : SelectionAdapter {
 139		override void widgetSelected(SelectionEvent e) { mixin(S_TRACE);
 140			raceToolTip();
 141		}
 142	}
 143	class BasicResist : SelectionAdapter {
 144		override void widgetSelected(SelectionEvent e) { mixin(S_TRACE);
 145			auto race = selectedRace;
 146			if (race) { mixin(S_TRACE);
 147				_automaton.setSelection(race.automaton);
 148				_constructure.setSelection(race.constructure);
 149				_undead.setSelection(race.undead);
 150				_unholy.setSelection(race.unholy);
 151				_resW.setSelection(race.weaponResist);
 152				_resM.setSelection(race.magicResist);
 153				foreach (el; _res.keys) { mixin(S_TRACE);
 154					_res[el].setSelection(race.resist(el));
 155					_weak[el].setSelection(race.weakness(el));
 156				}
 157			} else { mixin(S_TRACE);
 158				_automaton.setSelection(false);
 159				_constructure.setSelection(false);
 160				_undead.setSelection(false);
 161				_unholy.setSelection(false);
 162				_resW.setSelection(false);
 163				_resM.setSelection(false);
 164				foreach (el; _res.keys) { mixin(S_TRACE);
 165					_res[el].setSelection(false);
 166					_weak[el].setSelection(false);
 167				}
 168			}
 169		}
 170	}
 171	class BasicEnhance : SelectionAdapter {
 172		override void widgetSelected(SelectionEvent e) { mixin(S_TRACE);
 173			auto race = selectedRace;
 174			if (race) { mixin(S_TRACE);
 175				foreach (enh, i; _enhTbl) { mixin(S_TRACE);
 176					if (_enhR) { mixin(S_TRACE);
 177						_enhR.setValue(i, race.defaultEnhance(enh));
 178					} else { mixin(S_TRACE);
 179						_enhS.setValue(i, race.defaultEnhance(enh));
 180					}
 181				}
 182			} else { mixin(S_TRACE);
 183				foreach (enh, i; _enhTbl) { mixin(S_TRACE);
 184					if (_enhR) { mixin(S_TRACE);
 185						_enhR.setValue(i, 0);
 186					} else { mixin(S_TRACE);
 187						_enhS.setValue(i, 0);
 188					}
 189				}
 190			}
 191		}
 192	}
 193
 194	class SelLifeC : SelectionAdapter {
 195		override void widgetSelected(SelectionEvent e) { mixin(S_TRACE);
 196			auto vit = _phyTbl[Physical.VIT];
 197			auto min = _phyTbl[Physical.MIN];
 198			_lifeMax.setSelection(_prop.looks.lifeCalc(_level.getSelection(),
 199				(_phyR ? _phyR.getValue(vit) : _phyS.getValue(vit)),
 200				(_phyR ? _phyR.getValue(min) : _phyS.getValue(min))));
 201		}
 202	}
 203
 204	void constructBase(CTabFolder tabf) { mixin(S_TRACE);
 205		auto comp = new Composite(tabf, SWT.NONE);
 206		comp.setLayout(new GridLayout(2, false));
 207		auto skin = summSkin;
 208		{ mixin(S_TRACE);
 209			auto comp2 = new Composite(comp, SWT.NONE);
 210			comp2.setLayoutData(new GridData(GridData.FILL_BOTH));
 211			comp2.setLayout(zeroMarginGridLayout(1, false));
 212			{ mixin(S_TRACE);
 213				auto grp = new Group(comp2, SWT.NONE);
 214				grp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
 215				grp.setLayout(new GridLayout(2, false));
 216				grp.setText(_prop.msgs.name);
 217				_name = new GBLimitText(_prop.looks.monospace,
 218					_prop.looks.castNameLimit, false, grp, SWT.BORDER | _readOnly);
 219				_name.limitEvent ~= &refreshWarning;
 220				mod(_name.widget);
 221				createTextMenu!Text(_comm, _prop, _name.widget, &catchMod);
 222				auto gd = new GridData(GridData.FILL_HORIZONTAL);
 223				gd.widthHint = _name.computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
 224				_name.widget.setLayoutData(gd);
 225				auto l = new Label(grp, SWT.NONE);
 226				l.setText(.tryFormat(_prop.msgs.nameLimit, _prop.looks.castNameLimit, _prop.looks.castNameLimit / 2));
 227			}
 228			{ mixin(S_TRACE);
 229				bool including = _card && isBinImg(_card.path);
 230				_imgPath = new ImageSelect!(MtType.CARD)(comp2, _readOnly, _comm, _prop, _summ,
 231					_prop.looks.cardSize.width, _prop.looks.cardSize.height, including, true, &_name.getText);
 232				mod(_imgPath);
 233				_imgPath.modEvent ~= &refreshWarning;
 234				_imgPath.widget.setLayoutData(new GridData(GridData.FILL_BOTH));
 235				_imgPath.cardMode = CardMode.Cast;
 236			}
 237		}
 238		{ mixin(S_TRACE);
 239			auto compr = new Composite(comp, SWT.NONE);
 240			compr.setLayoutData(new GridData(GridData.FILL_VERTICAL));
 241			compr.setLayout(zeroMarginGridLayout(1, false));
 242			{ mixin(S_TRACE);
 243				auto grp = new Group(compr, SWT.NONE);
 244				grp.setLayoutData(new GridData(GridData.FILL_BOTH));
 245				grp.setLayout(new CenterLayout);
 246				grp.setText(_prop.msgs.level);
 247				auto comp2 = new Composite(grp, SWT.NONE);
 248				comp2.setLayout(zeroMarginGridLayout(2, false));
 249				_level = new Spinner(comp2, SWT.BORDER | _readOnly);
 250				initSpinner(_level);
 251				mod(_level);
 252				_level.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
 253				_level.setMinimum(1);
 254				_level.setMaximum(_prop.var.etc.castLevelMax);
 255				auto hint = new Label(comp2, SWT.RIGHT);
 256				hint.setText(.tryFormat(_prop.msgs.rangeHint, 1, _prop.var.etc.castLevelMax));
 257			}
 258			{ mixin(S_TRACE);
 259				auto grp = new Group(compr, SWT.NONE);
 260				grp.setLayoutData(new GridData(GridData.FILL_BOTH));
 261				grp.setLayout(new CenterLayout);
 262				grp.setText(_prop.msgs.life);
 263				auto comp2 = new Composite(grp, SWT.NONE);
 264				comp2.setLayout(zeroMarginGridLayout(2, false));
 265				_lifeMax = new Spinner(comp2, SWT.BORDER | _readOnly);
 266				initSpinner(_lifeMax);
 267				mod(_lifeMax);
 268				_lifeMax.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
 269				_lifeMax.setMinimum(1);
 270				_lifeMax.setMaximum(_prop.var.etc.lifeMax);
 271				_lifeMax.addModifyListener(new LifeMaxL);
 272				auto hint = new Label(comp2, SWT.RIGHT);
 273				hint.setText(.tryFormat(_prop.msgs.rangeHint, 1, _prop.var.etc.lifeMax));
 274				auto lifec = new Button(comp2, SWT.PUSH);
 275				mod(lifec);
 276				lifec.setEnabled(!_readOnly);
 277				auto lgd = new GridData(GridData.FILL_HORIZONTAL);
 278				lgd.horizontalSpan = 2;
 279				lifec.setLayoutData(lgd);
 280				lifec.setText(_prop.msgs.lifeCalc);
 281				lifec.addSelectionListener(new SelLifeC);
 282			}
 283			auto grp = new Group(compr, SWT.NONE);
 284			grp.setText(_prop.msgs.race);
 285			grp.setLayoutData(new GridData(GridData.FILL_BOTH));
 286			auto cl = new CenterLayout;
 287			cl.fillHorizontal = true;
 288			grp.setLayout(cl);
 289			_race = new Combo(grp, SWT.BORDER | SWT.DROP_DOWN | SWT.READ_ONLY);
 290			mod(_race);
 291			_race.setEnabled(!_readOnly);
 292			_race.setVisibleItemCount(_prop.var.etc.comboVisibleItemCount);
 293			_race.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
 294			_race.add(_prop.msgs.noRace);
 295			foreach (race; skin.races) { mixin(S_TRACE);
 296				_race.add(race.name);
 297			}
 298			_race.addSelectionListener(new SelectRace);
 299			refreshRace();
 300		}
 301		auto tab = new CTabItem(tabf, SWT.NONE);
 302		tab.setText(_prop.msgs.card);
 303		tab.setControl(comp);
 304	}
 305	void setMaxLife() { mixin(S_TRACE);
 306		_life.setMaximum(_lifeMax.getSelection());
 307		if (_lifeUseMax.getSelection()) { mixin(S_TRACE);
 308			_life.setSelection(_lifeMax.getSelection());
 309		}
 310		_life.getParent().layout();
 311		_life.setSelection(_life.getSelection());
 312	}
 313	class LifeMaxL : ModifyListener {
 314		public override void modifyText(ModifyEvent e) { mixin(S_TRACE);
 315			setMaxLife();
 316		}
 317	}
 318	void constructDesc(CTabFolder tabf) { mixin(S_TRACE);
 319		auto comp = new Composite(tabf, SWT.NONE);
 320		comp.setLayout(new GridLayout(2, false));
 321		{ mixin(S_TRACE);
 322			auto grp = new Group(comp, SWT.NONE);
 323			auto gd = new GridData(GridData.FILL_BOTH);
 324			grp.setLayoutData(gd);
 325			gd.horizontalSpan = 2;
 326			auto cl = new CenterLayout(SWT.HORIZONTAL);
 327			cl.fillVertical = true;
 328			grp.setLayout(cl);
 329			grp.setText(_prop.msgs.desc);
 330			_desc = new FixedWidthText(dwtData(_prop.looks.cardDescFont(_summ.legacy)), _prop.looks.cardDescLen, grp, SWT.BORDER | _readOnly);
 331			mod(_desc.widget);
 332			createTextMenu!Text(_comm, _prop, _desc.widget, &catchMod);
 333			auto p = _desc.computeTextBaseSize(1);
 334			p.y = SWT.DEFAULT;
 335			_desc.widget.setLayoutData(p);
 336		}
 337		auto tab = new CTabItem(tabf, SWT.NONE);
 338		tab.setText(_prop.msgs.desc);
 339		tab.setControl(comp);
 340	}
 341	Button createR(Composite parent, string name, int hAlignHint = -1) { mixin(S_TRACE);
 342		auto radio = new Button(parent, SWT.RADIO);
 343		mod(radio);
 344		radio.setEnabled(!_readOnly);
 345		auto gd = new GridData(GridData.FILL_BOTH);
 346		if (0 <= hAlignHint) { mixin(S_TRACE);
 347			hAlignHint %= 2;
 348			gd.grabExcessHorizontalSpace = true;
 349			if (0 == hAlignHint) { mixin(S_TRACE);
 350				gd.horizontalAlignment = SWT.LEFT;
 351			} else { mixin(S_TRACE);
 352				gd.horizontalAlignment = SWT.RIGHT;
 353			}
 354		}
 355		radio.setLayoutData(gd);
 356		radio.setText(name);
 357		return radio;
 358	}
 359	void constructHistory(CTabFolder tabf) { mixin(S_TRACE);
 360		auto comp = new Composite(tabf, SWT.NONE);
 361		comp.setLayout(new GridLayout(2, false));
 362		auto skin = summSkin;
 363		{ mixin(S_TRACE);
 364			auto grp = new Group(comp, SWT.NONE);
 365			grp.setText(_prop.msgs.coupons);
 366			grp.setLayoutData(new GridData(GridData.FILL_BOTH));
 367			grp.setLayout(new GridLayout(1, true));
 368			_couponView = new CouponView!(CVType.Cast)(_comm, _summ, grp, _readOnly, &catchMod);
 369			_couponView.setLayoutData(new GridData(GridData.FILL_BOTH));
 370			mod(_couponView);
 371		}
 372		{ mixin(S_TRACE);
 373			auto comp2 = new Composite(comp, SWT.NONE);
 374			comp2.setLayoutData(new GridData(GridData.FILL_VERTICAL));
 375			comp2.setLayout(zeroMarginGridLayout(2, false));
 376			{ mixin(S_TRACE);
 377				auto comp3 = createButtonGroup(comp2, _prop.msgs.sexTitle, 1, 1);
 378				foreach (s; SEX_ALL) { mixin(S_TRACE);
 379					auto name = skin.sexName(s);
 380					_sex[s] = createR(comp3, _prop.msgs.sex.get(name, name));
 381				}
 382				_sexU = createR(comp3, _prop.msgs.sexUnknown);
 383			}
 384			{ mixin(S_TRACE);
 385				auto comp3 = createButtonGroup(comp2, _prop.msgs.periodTitle, 2, 1);
 386				foreach (p; PERIOD_ALL) { mixin(S_TRACE);
 387					auto name = skin.periodName(p);
 388					_period[p] = createR(comp3, _prop.msgs.period.get(name, name));
 389				}
 390				_periodU = createR(comp3, _prop.msgs.periodUnknown);
 391			}
 392			{ mixin(S_TRACE);
 393				auto comp3 = new Group(comp2, SWT.NONE);
 394				comp3.setText(_prop.msgs.natureTitle);
 395				auto cgd = new GridData(GridData.FILL_BOTH);
 396				cgd.horizontalSpan = 2;
 397				comp3.setLayoutData(cgd);
 398				comp3.setLayout(new GridLayout(2, true));
 399				_natureComp = comp3;
 400				updateNature();
 401			}
 402		}
 403		auto tab = new CTabItem(tabf, SWT.NONE);
 404		tab.setText(_prop.msgs.history);
 405		tab.setControl(comp);
 406	}
 407	class MSListener : SelectionAdapter {
 408		override void widgetSelected(SelectionEvent e) { mixin(S_TRACE);
 409			auto radio = cast(Button) e.widget;
 410			if (radio.getSelection()) { mixin(S_TRACE);
 411				auto m = cast(Makings) (cast(Integer) radio.getData()).intValue();
 412				auto r = reverseMakings(m);
 413				_makings[r].setSelection(false);
 414			}
 415		}
 416	};
 417	void constructMakings(CTabFolder tabf) { mixin(S_TRACE);
 418		auto comp = new Composite(tabf, SWT.NONE);
 419		comp.setLayout(new GridLayout(1, false));
 420		auto skin = summSkin;
 421		{ mixin(S_TRACE);
 422			auto comp3 = createButtonGroup(comp, _prop.msgs.coupons, 4, 1, true);
 423			auto sl = new MSListener;
 424			foreach (m; MAKINGS_LEFT) { mixin(S_TRACE);
 425				void createR(Makings m) { mixin(S_TRACE);
 426					auto radio = new Button(comp3, SWT.CHECK);
 427					mod(radio);
 428					radio.setEnabled(!_readOnly);
 429					radio.setLayoutData(new GridData(GridData.FILL_BOTH));
 430					auto name = skin.makingsName(m);
 431					radio.setText(_prop.msgs.makings.get(name, name));
 432					radio.setData(new Integer(m));
 433					radio.addSelectionListener(sl);
 434					_makings[m] = radio;
 435				}
 436				createR(m);
 437				createR(reverseMakings(m));
 438			}
 439		}
 440		auto tab = new CTabItem(tabf, SWT.NONE);
 441		tab.setText(_prop.msgs.makingsTitle);
 442		tab.setControl(comp);
 443	}
 444	Composite createButtonGroup(Composite parent, string name,
 445			int row, int horSpan = 1, bool min = false) { mixin(S_TRACE);
 446		auto grp = new Group(parent, SWT.NONE);
 447		grp.setText(name);
 448		auto gd = new GridData(GridData.FILL_BOTH);
 449		gd.horizontalSpan = horSpan;
 450		grp.setLayoutData(gd);
 451		auto cl = new CenterLayout(SWT.HORIZONTAL | SWT.VERTICAL, 0);
 452		cl.fillVertical = true;
 453		grp.setLayout(cl);
 454		auto comp3 = new Composite(grp, SWT.NONE);
 455		auto gl = new GridLayout(row, true);
 456		if (min) gl.verticalSpacing = 2;
 457		comp3.setLayout(gl);
 458		return comp3;
 459	}
 460	class ESListener : SelectionAdapter {
 461		private Button _targ;
 462		this(Button targ) { mixin(S_TRACE);
 463			_targ = targ;
 464		}
 465		override void widgetSelected(SelectionEvent e) { mixin(S_TRACE);
 466			auto radio = cast(Button) e.widget;
 467			if (radio.getSelection()) { mixin(S_TRACE);
 468				_targ.setSelection(false);
 469			}
 470		}
 471	};
 472	void constructResist(CTabFolder tabf) { mixin(S_TRACE);
 473		auto comp = new Composite(tabf, SWT.NONE);
 474		comp.setLayout(new GridLayout(1, false));
 475		Button createC(Composite parent, string name, string desc) { mixin(S_TRACE);
 476			auto comp = new Composite(parent, SWT.NONE);
 477			comp.setLayoutData(new GridData(GridData.FILL_BOTH));
 478			comp.setLayout(zeroGridLayout(2, false));
 479			auto c = new Button(comp, SWT.CHECK);
 480			mod(c);
 481			c.setEnabled(!_readOnly);
 482			auto cgd = new GridData(GridData.FILL_HORIZONTAL);
 483			cgd.horizontalSpan = 2;
 484			c.setLayoutData(cgd);
 485			c.setText(name);
 486			auto dummy = new Composite(comp, SWT.NONE);
 487			auto dgd = new GridData;
 488			dgd.widthHint = 20;
 489			dgd.heightHint = 0;
 490			dummy.setLayoutData(dgd);
 491			auto l = new Label(comp, SWT.NONE);
 492			l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
 493			l.setText(desc);
 494			return c;
 495		}
 496		{ mixin(S_TRACE);
 497			Composite tcomp, bcomp;
 498			{ mixin(S_TRACE);
 499				tcomp = createButtonGroup(comp, _prop.msgs.tolerantBase, 2, 1);
 500				auto gl = cast(GridLayout) tcomp.getLayout();
 501				gl.horizontalSpacing = 15;
 502				_resW = createC(tcomp, _prop.msgs.resistWeapon, _prop.msgs.descResistWeapon);
 503				_resM = createC(tcomp, _prop.msgs.resistMagic, _prop.msgs.descResistMagic);
 504			}
 505			{ mixin(S_TRACE);
 506				bcomp = createButtonGroup(comp, _prop.msgs.tolerantElement, 2, 1);
 507				auto gl = cast(GridLayout) bcomp.getLayout();
 508				gl.horizontalSpacing = 15;
 509				_undead = createC(bcomp, _prop.msgs.undead, _prop.msgs.descUndead);
 510				_automaton = createC(bcomp, _prop.msgs.automaton, _prop.msgs.descAutomaton);
 511				_unholy = createC(bcomp, _prop.msgs.unholy, _prop.msgs.descUnholy);
 512				_constructure = createC(bcomp, _prop.msgs.constructure, _prop.msgs.descConstructure);
 513				foreach (e; [Element.FIRE, Element.ICE]) { mixin(S_TRACE);
 514					string eName = _prop.msgs.elementName(e);
 515					auto res = createC(bcomp, .tryFormat(_prop.msgs.resistText, eName), .tryFormat(_prop.msgs.descResist, eName));
 516					auto weak = createC(bcomp, .tryFormat(_prop.msgs.weaknessText, eName), .tryFormat(_prop.msgs.descWeakness, eName));
 517					res.addSelectionListener(new ESListener(weak));
 518					weak.addSelectionListener(new ESListener(res));
 519					_res[e] = res;
 520					_weak[e] = weak;
 521				}
 522			}
 523			auto ts = tcomp.computeSize(SWT.DEFAULT, SWT.DEFAULT);
 524			auto bs = bcomp.computeSize(SWT.DEFAULT, SWT.DEFAULT);
 525			int maxW = ts.x > bs.x ? ts.x : bs.x;
 526			ts.x = maxW;
 527			bs.x = maxW;
 528			tcomp.setLayoutData(ts);
 529			bcomp.setLayoutData(bs);
 530		}
 531		{ mixin(S_TRACE);
 532			auto basic = new Button(comp, SWT.PUSH);
 533			mod(basic);
 534			basic.setEnabled(!_readOnly);
 535			basic.setText(_prop.msgs.basicResist);
 536			basic.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
 537			basic.addSelectionListener(new BasicResist);
 538		}
 539		auto tab = new CTabItem(tabf, SWT.NONE);
 540		tab.setText(_prop.msgs.tolerant);
 541		tab.setControl(comp);
 542	}
 543	static immutable PHYSICALS = [Physical.DEX, Physical.AGL, Physical.INT,
 544		Physical.STR, Physical.VIT, Physical.MIN];
 545	void initPhysical() { mixin(S_TRACE);
 546		int[] values = [];
 547		if (_phyR) { mixin(S_TRACE);
 548			values = _phyR.getValues();
 549			_phyR.dispose();
 550			_phyR = null;
 551		}
 552		if (_phyS) { mixin(S_TRACE);
 553			values = _phyS.getValues();
 554			_phyS.dispose();
 555			_phyS = null;
 556		}
 557
 558		string[] names;
 559		names.length = PHYSICALS.length;
 560		int[Physical] table;
 561		foreach (i, p; PHYSICALS) { mixin(S_TRACE);
 562			table[p] = i;
 563			names[i] = _prop.msgs.physicalName(p);
 564		}
 565		_phyTbl = table;
 566		int page = _prop.var.etc.physicalMax / 5;
 567
 568		if (_prop.var.etc.radarStyleParams) { mixin(S_TRACE);
 569			_phyR = new RadarSpinner(_phyParent, _readOnly);
 570			_phyR.setRadar(_prop.var.etc.physicalMax + 1, names, 0);
 571			_phyR.antialias = true;
 572			_phyR.borderlines = cast(int[]) _prop.looks.physicalBorders;
 573			_phyR.lineStep = page;
 574			if (values.length) _phyR.setValues(values);
 575			mod(_phyR);
 576			_phyR.modEvent ~= &modPhysical;
 577		} else { mixin(S_TRACE);
 578			_phyS = new Scales(_phyParent, _readOnly);
 579			_phyS.setScales(_prop.var.etc.physicalMax + 1, names, page, 0);
 580			_phyS.borderlines = cast(int[]) _prop.looks.physicalBorders;
 581			if (values.length) _phyS.setValues(values);
 582			mod(_phyS);
 583			_phyS.modEvent ~= &modPhysical;
 584		}
 585		_phyParent.layout();
 586	}
 587	void modPhysical() { mixin(S_TRACE);
 588		int[] vals;
 589		if (_phyR) vals = _phyR.getValues();
 590		if (_phyS) vals = _phyS.getValues();
 591		int sum = 0;
 592		foreach (val; vals) { mixin(S_TRACE);
 593			sum += val;
 594		}
 595		_sumPhy.setText(.tryFormat(_prop.msgs.physicalSum, sum));
 596	}
 597	void constructPhysical(CTabFolder tabf) { mixin(S_TRACE);
 598		auto comp = new Composite(tabf, SWT.NONE);
 599		comp.setLayout(new GridLayout(2, false));
 600		{ mixin(S_TRACE);
 601			auto grp = new Group(comp, SWT.NONE);
 602			grp.setText(_prop.msgs.physicalParams);
 603			auto gd = new GridData(GridData.FILL_BOTH);
 604			gd.horizontalSpan = 2;
 605			grp.setLayoutData(gd);
 606			auto cl = new CenterLayout;
 607			cl.fillHorizontal = true;
 608			cl.fillVertical = true;
 609			grp.setLayout(cl);
 610			_phyParent = grp;
 611			initPhysical();
 612		}
 613		{ mixin(S_TRACE);
 614			_sumPhy = new Label(comp, SWT.NONE);
 615			_sumPhy.setLayoutData(new GridData(GridData.FILL_HORIZONTAL|GridData.HORIZONTAL_ALIGN_BEGINNING));
 616		}
 617		{ mixin(S_TRACE);
 618			auto basic = new Button(comp, SWT.PUSH);
 619			mod(basic);
 620			basic.setEnabled(!_readOnly);
 621			basic.setText(_prop.msgs.physicalCalc);
 622			basic.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
 623			basic.addSelectionListener(new CalcPhysical);
 624		}
 625		auto tab = new CTabItem(tabf, SWT.NONE);
 626		tab.setText(_prop.msgs.physicalParams);
 627		tab.setControl(comp);
 628	}
 629	real calcPhy(E)(in Skin skin, Physical phy, Button[E] radios, bool all) { mixin(S_TRACE);
 630		real r = 0.0;
 631		foreach (e, radio; radios) { mixin(S_TRACE);
 632			if (radio.getSelection()) { mixin(S_TRACE);
 633				r += skin.physicalMod(e, phy);
 634				if (!all) break;
 635			}
 636		}
 637		return r;
 638	}
 639	class CalcPhysical : SelectionAdapter {
 640		override void widgetSelected(SelectionEvent e) { mixin(S_TRACE);
 641			real[Physical] p;
 642			int[Physical] min;
 643			int[Physical] max;
 644			auto race = selectedRace;
 645			foreach (phy; _phyTbl.keys) { mixin(S_TRACE);
 646				int pmin = _prop.looks.physicalCutMin;
 647				int pmax;
 648				if (race) { mixin(S_TRACE);
 649					int v = race.physical(phy);
 650					pmax = v + _prop.looks.physicalCutMaxBase;
 651					if (pmax > _prop.var.etc.physicalMax) pmax = _prop.var.etc.physicalMax;
 652					if (v < pmin) pmin = v;
 653					p[phy] = v;
 654				} else { mixin(S_TRACE);
 655					int v = _prop.looks.physicalNormal;
 656					pmax = v + _prop.looks.physicalCutMaxBase;
 657					p[phy] = v;
 658				}
 659				min[phy] = pmin;
 660				max[phy] = pmax;
 661			}
 662			foreach (phy, val; p) { mixin(S_TRACE);
 663				val += calcPhy!(Sex)(summSkin, phy, _sex, false);
 664				val += calcPhy!(Period)(summSkin, phy, _period, false);
 665				val += calcPhy!(Nature)(summSkin, phy, _nature, false);
 666				val += calcPhy!(Makings)(summSkin, phy, _makings, true);
 667				p[phy] = val;
 668			}
 669			int[] vals;
 670			vals.length = p.length;
 671			foreach (phy, val; p) { mixin(S_TRACE);
 672				int v = cast(int) val;
 673				if (v < min[phy]) v = min[phy];
 674				if (v > max[phy]) v = max[phy];
 675				vals[_phyTbl[phy]] = v;
 676			}
 677			if (_phyR) { mixin(S_TRACE);
 678				_phyR.setValues(vals);
 679			} else { mixin(S_TRACE);
 680				_phyS.setValues(vals);
 681			}
 682			modPhysical();
 683		}
 684	}
 685	void constructMental(CTabFolder tabf) { mixin(S_TRACE);
 686		auto comp = new Composite(tabf, SWT.NONE);
 687		comp.setLayout(new GridLayout(1, false));
 688		{ mixin(S_TRACE);
 689			auto grp = new Group(comp, SWT.NONE);
 690			grp.setText(_prop.msgs.mentalParams);
 691			grp.setLayoutData(new GridData(GridData.FILL_BOTH));
 692			auto ggl = new GridLayout(3, false);
 693			ggl.verticalSpacing = 0;
 694			grp.setLayout(ggl);
 695			static const Ms = [Mental.AGGRESSIVE, Mental.CHEERFUL, Mental.BRAVE,
 696				Mental.CAUTIOUS, Mental.TRICKISH];
 697			foreach (m; Ms) { mixin(S_TRACE);
 698				auto minl = new Label(grp, SWT.NONE);
 699				minl.setText(_prop.msgs.mentalName(reverseMental(m)));
 700				auto scale = new Scale(grp, SWT.NONE);
 701				mod(scale);
 702				scale.setEnabled(!_readOnly);
 703				scale.setLayoutData(new GridData(GridData.FILL_BOTH));
 704				scale.setMaximum(_prop.var.etc.mentalMax * 2);
 705				scale.setMinimum(0);
 706				scale.setIncrement(1);
 707				scale.setPageIncrement(_prop.var.etc.mentalMax);
 708				auto maxl = new Label(grp, SWT.NONE);
 709				maxl.setText(_prop.msgs.mentalName(m));
 710				_mtl[m] = scale;
 711			}
 712		}
 713		{ mixin(S_TRACE);
 714			auto basic = new Button(comp, SWT.PUSH);
 715			mod(basic);
 716			basic.setEnabled(!_readOnly);
 717			basic.setText(_prop.msgs.mentalCalc);
 718			basic.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
 719			basic.addSelectionListener(new CalcMental);
 720		}
 721		auto tab = new CTabItem(tabf, SWT.NONE);
 722		tab.setText(_prop.msgs.mentalParams);
 723		tab.setControl(comp);
 724	}
 725	real calcMtl(E)(in Skin skin, Mental mtl, Button[E] radios, bool all) { mixin(S_TRACE);
 726		real r = 0.0;
 727		foreach (e, radio; radios) { mixin(S_TRACE);
 728			if (radio.getSelection()) { mixin(S_TRACE);
 729				r += skin.mentalMod(e, mtl);
 730				if (!all) break;
 731			}
 732		}
 733		return r;
 734	}
 735	class CalcMental : SelectionAdapter {
 736		override void widgetSelected(SelectionEvent e) { mixin(S_TRACE);
 737			auto race = selectedRace;
 738			foreach (mtl, scale; _mtl) { mixin(S_TRACE);
 739				int min = cast(int) _prop.looks.mentalCut * -1;
 740				int max = _prop.looks.mentalCut;
 741				real val;
 742				if (race) { mixin(S_TRACE);
 743					int ival = race.mental(mtl);
 744					val = ival;
 745					if (ival < min) min = ival;
 746					if (ival > max) max = ival;
 747				} else { mixin(S_TRACE);
 748					val = 0.0;
 749				}
 750				val += calcMtl!(Sex)(summSkin, mtl, _sex, false);
 751				val += calcMtl!(Period)(summSkin, mtl, _period, false);
 752				val += calcMtl!(Nature)(summSkin, mtl, _nature, false);
 753				val += calcMtl!(Makings)(summSkin, mtl, _makings, true);
 754				int v = cast(int) val;
 755				if (v < min) v = min;
 756				if (v > max) v = max;
 757				scale.setSelection(v + _prop.var.etc.mentalMax);
 758			}
 759		}
 760	}
 761	static immutable ENHANCE = [Enhance.AVOID, Enhance.RESIST, Enhance.DEFENSE];
 762	void initEnhance() { mixin(S_TRACE);
 763		int[] values = [];
 764		if (_enhR) { mixin(S_TRACE);
 765			values = _enhR.getValues();
 766			_enhR.dispose();
 767			_enhR = null;
 768		}
 769		if (_enhS) { mixin(S_TRACE);
 770			values = _enhS.getValues();
 771			_enhS.dispose();
 772			_enhS = null;
 773		}
 774
 775		string[] names;
 776		names.length = ENHANCE.length;
 777		foreach (i, enh; ENHANCE) { mixin(S_TRACE);
 778			_enhTbl[enh] = i;
 779			names[i] = .tryFormat(_prop.msgs.enhanceBonus, _prop.msgs.enhanceName(enh));
 780		}
 781		int stepC = _prop.var.etc.enhanceMax * 2 + 1;
 782		int min = cast(int) _prop.var.etc.enhanceMax * -1;
 783		int page = _prop.var.etc.enhanceMax / 2;
 784		if (_prop.var.etc.radarStyleParams) { mixin(S_TRACE);
 785			_enhR = new RadarSpinner(_enhParent, _readOnly);
 786			_enhR.setRadar(stepC, names, min);
 787			_enhR.antialias = true;
 788			_enhR.borderlines = [0];
 789			_enhR.lineStep = page;
 790			if (values.length) _enhR.setValues(values);
 791			mod(_enhR);
 792		} else { mixin(S_TRACE);
 793			_enhS = new Scales(_enhParent, _readOnly);
 794			_enhS.setScales(stepC, names, page, min);
 795			_enhS.borderlines = [0];
 796			if (values.length) _enhS.setValues(values);
 797			mod(_enhS);
 798		}
 799		_enhParent.layout();
 800	}
 801	void constructEnhance(CTabFolder tabf) { mixin(S_TRACE);
 802		auto comp = new Composite(tabf, SWT.NONE);
 803		comp.setLayout(new GridLayout(1, false));
 804		{ mixin(S_TRACE);
 805			auto grp = new Group(comp, SWT.NONE);
 806			grp.setText(_prop.msgs.castEnhance);
 807			grp.setLayoutData(new GridData(GridData.FILL_BOTH));
 808			auto cl = new CenterLayout;
 809			cl.fillHorizontal = true;
 810			cl.fillVertical = true;
 811			grp.setLayout(cl);
 812			_enhParent = grp;
 813			initEnhance();
 814		}
 815		{ mixin(S_TRACE);
 816			auto basic = new Button(comp, SWT.PUSH);
 817			mod(basic);
 818			basic.setEnabled(!_readOnly);
 819			basic.setText(_prop.msgs.basicEnhance);
 820			basic.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
 821			basic.addSelectionListener(new BasicEnhance);
 822		}
 823		auto tab = new CTabItem(tabf, SWT.NONE);
 824		tab.setText(_prop.msgs.castEnhance);
 825		tab.setControl(comp);
 826	}
 827	void constructStatus(CTabFolder tabf) { mixin(S_TRACE);
 828		auto comp = new Composite(tabf, SWT.NONE);
 829		comp.setLayout(new GridLayout(1, false));
 830		Label[] lbls1, lbls2;
 831		Composite[] spns;
 832		Spinner createSpn(Composite comp) { mixin(S_TRACE);
 833			// ???Composite???????Spinner#computeSize()?????????
 834			Composite comp2 = new Composite(comp, SWT.NONE);
 835			comp2.setLayout(new FillLayout);
 836			auto spn = new Spinner(comp2, SWT.BORDER | _readOnly);
 837			initSpinner(spn);
 838			mod(spn);
 839			spns ~= comp2;
 840			return spn;
 841		}
 842		Composite createGrp(string text) { mixin(S_TRACE);
 843			auto grp = new Group(comp, SWT.NONE);
 844			grp.setLayoutData(new GridData(GridData.FILL_BOTH));
 845			auto gl = new GridLayout(2, false);
 846			gl.horizontalSpacing = 15;
 847			grp.setLayout(gl);
 848			grp.setText(text);
 849			return grp;
 850		}
 851		Composite createComp(Composite grp) { mixin(S_TRACE);
 852			auto comp2 = new Composite(grp, SWT.NONE);
 853			comp2.setLayoutData(new GridData(GridData.FILL_BOTH));
 854			auto rl = new RowLayout(SWT.HORIZONTAL);
 855			rl.center = true;
 856			rl.marginLeft = 0;
 857			rl.marginRight = 0;
 858			rl.marginTop = 0;
 859			rl.marginBottom = 0;
 860			comp2.setLayout(rl);
 861			return comp2;
 862		}
 863		{ mixin(S_TRACE);
 864			auto grp = createGrp(_prop.msgs.lifeAndMentality);
 865			{ mixin(S_TRACE);
 866				auto comp2 = createComp(grp);
 867				auto l = new Label(comp2, SWT.NONE);
 868				l.setText(_prop.msgs.life);
 869				lbls1 ~= l;
 870				_life = new Spinner(comp2, SWT.BORDER | _readOnly);
 871				initSpinner(_life);
 872				mod(_life);
 873				_lifeUseMax = new Button(comp2, SWT.CHECK);
 874				mod(_lifeUseMax);
 875				_lifeUseMax.setEnabled(!_readOnly);
 876				_lifeUseMax.setText(_prop.msgs.useMax);
 877				_lifeUseMax.addSelectionListener(new LifeUseMax);
 878			}
 879			{ mixin(S_TRACE);
 880				auto comp2 = createComp(grp);
 881				auto lm = new Label(comp2, SWT.NONE);
 882				lm.setText(_prop.msgs.mentality);
 883				lbls1 ~= lm;
 884				_mtly = new Combo(comp2, SWT.BORDER | SWT.DROP_DOWN | SWT.READ_ONLY);
 885				mod(_mtly);
 886				_mtly.setEnabled(!_readOnly);
 887				_mtly.setVisibleItemCount(_prop.var.etc.comboVisibleItemCount);
 888				foreach (i, mtly; [Mentality.NORMAL, Mentality.SLEEP, Mentality.CONFUSE,
 889						Mentality.OVERHEAT, Mentality.BRAVE, Mentality.PANIC]) { mixin(S_TRACE);
 890					_mtly.add(_prop.msgs.mentalityName(mtly));
 891					_mtlyTbl[i] = mtly;
 892					if (_card && _card.mentality is mtly) { mixin(S_TRACE);
 893						_mtly.select(i);
 894					}
 895				}
 896				if (_mtly.getSelectionIndex() < 0) _mtly.select(0);
 897				_mtly.addSelectionListener(new SelMentality);
 898				_mtlyRound = createSpn(comp2);
 899				_mtlyRound.setMaximum(_prop.var.etc.roundMax);
 900				_mtlyRound.setMinimum(Motion.round_min);
 901				spns ~= _mtlyRound;
 902				auto lm2  = new Label(comp2, SWT.NONE);
 903				lm2.setText(_prop.msgs.unitRound);
 904			}
 905		}
 906		{ mixin(S_TRACE);
 907			auto grp = createGrp(_prop.msgs.enhanceLiveBonus);
 908			foreach (enh; [Enhance.ACTION, Enhance.AVOID, Enhance.RESIST, Enhance.DEFENSE]) { mixin(S_TRACE);
 909				auto comp2 = createComp(grp);
 910				auto l = new Label(comp2, SWT.NONE);
 911				l.setText(_prop.msgs.enhanceLiveBonusName(enh));
 912				lbls1 ~= l;
 913				auto spn = createSpn(comp2);
 914				spn.setMaximum(_prop.var.etc.enhanceMax);
 915				spn.setMinimum(-(cast(int) _prop.var.etc.enhanceMax));
 916				spns ~= spn;
 917				_liveEnh[enh] = spn;
 918				auto rnd = createSpn(comp2);
 919				rnd.setMaximum(_prop.var.etc.roundMax);
 920				rnd.setMinimum(Motion.round_min);
 921				spns ~= rnd;
 922				_enhRound[enh] = rnd;
 923				auto l2  = new Label(comp2, SWT.NONE);
 924				l2.setText(_prop.msgs.unitRound);
 925				spn.addSelectionListener(new LiveEnh);
 926			}
 927		}
 928		Spinner createStSpn(Composite grp, string name, uint max, string val) { mixin(S_TRACE);
 929			auto comp2 = createComp(grp);
 930			auto l = new Label(comp2, SWT.NONE);
 931			l.setText(name);
 932			lbls1 ~= l;
 933			auto spn = createSpn(comp2);
 934			spn.setMaximum(max);
 935			spn.setMinimum(0);
 936			spns ~= spn;
 937			auto l2  = new Label(comp2, SWT.NONE);
 938			l2.setText(val);
 939			lbls2 ~= l2;
 940			return spn;
 941		}
 942		{ mixin(S_TRACE);
 943			auto grp = createGrp(_prop.msgs.status);
 944			_paralyze = createStSpn(grp, _prop.msgs.paralyze, _prop.var.etc.paralyzeMax, _prop.msgs.unitValue);
 945			_poison = createStSpn(grp, _prop.msgs.poison, _prop.var.etc.poisonMax, _prop.msgs.unitValue);
 946			_bind = createStSpn(grp, _prop.msgs.bind, _prop.var.etc.roundMax, _prop.msgs.unitRound);
 947			_silence = createStSpn(grp, _prop.msgs.silence, _prop.var.etc.roundMax, _prop.msgs.unitRound);
 948			_faceUp = createStSpn(grp, _prop.msgs.faceUp, _prop.var.etc.roundMax, _prop.msgs.unitRound);
 949			_antiMagic = createStSpn(grp, _prop.msgs.antiMagic, _prop.var.etc.roundMax, _prop.msgs.unitRound);
 950		}
 951		void setlblw(Control[] lbls) { mixin(S_TRACE);
 952			int maxW = 0;
 953			foreach (lbl; lbls) { mixin(S_TRACE);
 954				int w = lbl.computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
 955				if (maxW < w) maxW = w;
 956			}
 957			foreach (lbl; lbls) { mixin(S_TRACE);
 958				auto gd = new RowData(maxW, SWT.DEFAULT);
 959				lbl.setLayoutData(gd);
 960			}
 961		}
 962		setlblw(cast(Control[]) lbls1);
 963		setlblw(cast(Control[]) lbls2);
 964		setlblw(cast(Control[]) spns);
 965		{ mixin(S_TRACE);
 966			auto reset = new Button(comp, SWT.PUSH);
 967			mod(reset);
 968			reset.setEnabled(!_readOnly);
 969			reset.setText(_prop.msgs.resetLiveStatus);
 970			reset.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
 971			reset.addSelectionListener(new ResetLiveStatus);
 972		}
 973		auto tab = new CTabItem(tabf, SWT.NONE);
 974		tab.setText(_prop.msgs.liveStatus);
 975		tab.setControl(comp);
 976	}
 977	class LiveEnh : SelectionAdapter {
 978		override void widgetSelected(SelectionEvent e) { mixin(S_TRACE);
 979			changeLiveEnhance();
 980		}
 981	}
 982	class SelMentality : SelectionAdapter {
 983		override void widgetSelected(SelectionEvent e) { mixin(S_TRACE);
 984			changeMentality();
 985		}
 986	}
 987	class LifeUseMax : SelectionAdapter {
 988		override void widgetSelected(SelectionEvent e) { mixin(S_TRACE);
 989			changeLifeUseMax();
 990		}
 991	}
 992	class ResetLiveStatus : SelectionAdapter {
 993		override void widgetSelected(SelectionEvent e) { mixin(S_TRACE);
 994			resetLiveStatus();
 995		}
 996	}
 997	void changeLiveEnhance() { mixin(S_TRACE);
 998		foreach (enh, spn; _liveEnh) { mixin(S_TRACE);
 999			_enhRound[enh].setEnabled(!_readOnly && spn.getSelection() != 0);
1000		}
1001	}
1002	void changeMentality() { mixin(S_TRACE);
1003		_mtlyRound.setEnabled(!_readOnly && _mtly.getSelectionIndex() != 0);
1004	}
1005	void changeLifeUseMax() { mixin(S_TRACE);
1006		_life.setEnabled(!_readOnly && !_lifeUseMax.getSelection());
1007	}
1008	void resetLiveStatus() { mixin(S_TRACE);
1009		_life.setSelection(_lifeMax.getSelection());
1010		_lifeUseMax.setSelection(true);
1011		foreach (enh, spn; _liveEnh) { mixin(S_TRACE);
1012			spn.setSelection(0);
1013		}
1014		foreach (enh, spn; _enhRound) { mixin(S_TRACE);
1015			spn.setSelection(0);
1016		}
1017		_paralyze.setSelection(0);
1018		_poison.setSelection(0);
1019		_bind.setSelection(0);
1020		_silence.setSelection(0);
1021		_faceUp.setSelection(0);
1022		_antiMagic.setSelection(0);
1023		_mtly.select(0);
1024		_mtlyRound.setSelection(0);
1025		changeLiveEnhance();
1026		changeMentality();
1027		changeLifeUseMax();
1028	}
1029	void delCard(CastCard c) { mixin(S_TRACE);
1030		if (_card is c) { mixin(S_TRACE);
1031			forceCancel();
1032		}
1033	}
1034	void refScenario(Summary summ) { mixin(S_TRACE);
1035		forceCancel();
1036	}
1037	class Dispose : DisposeListener {
1038		override void widgetDisposed(DisposeEvent e) { mixin(S_TRACE);
1039			_comm.refRadarStyle.remove(&initPhysical);
1040			_comm.refRadarStyle.remove(&initEnhance);
1041			_comm.delCast.remove(&delCard);
1042			_comm.refScenario.remove(&refScenario);
1043			_comm.refSkin.remove(&refSkin);
1044			_comm.refCoupons.remove(&updateNature);
1045		}
1046	}
1047	void refSkin() { mixin(S_TRACE);
1048		_desc.font = dwtData(_prop.looks.cardDescFont(_summ.legacy));
1049		refreshRace();
1050		refreshSex();
1051		refreshPeriod();
1052		refreshNature();
1053		refreshMakings();
1054	}
1055	void refreshRace() { mixin(S_TRACE);
1056		_race.setEnabled(!_readOnly && !_summ.legacy);
1057	}
1058	void refreshSex() { mixin(S_TRACE);
1059		foreach (s, b; _sex) { mixin(S_TRACE);
1060			auto name = summSkin.sexName(s);
1061			b.setText(_prop.msgs.sex.get(name, name));
1062		}
1063	}
1064	void refreshPeriod() { mixin(S_TRACE);
1065		foreach (p, b; _period) { mixin(S_TRACE);
1066			auto name = summSkin.periodName(p);
1067			b.setText(_prop.msgs.period.get(name, name));
1068		}
1069	}
1070	void refreshNature() { mixin(S_TRACE);
1071		foreach (n, b; _nature) { mixin(S_TRACE);
1072			auto name = summSkin.natureName(n);
1073			b.setText(_prop.msgs.nature.get(name, name));
1074		}
1075	}
1076	void refreshMakings() { mixin(S_TRACE);
1077		foreach (m, b; _makings) { mixin(S_TRACE);
1078			auto name = summSkin.makingsName(m);
1079			b.setText(_prop.msgs.makings.get(name, name));
1080		}
1081	}
1082
1083	void updateNature() { mixin(S_TRACE);
1084		if (getShell().isVisible()) getShell().setRedraw(false);
1085		scope (exit) {
1086			if (getShell().isVisible()) getShell().setRedraw(true);
1087		}
1088
1089		bool first = (0 == _natureComp.getChildren().length);
1090		string nature = "";
1091		if (first || _showSpNature != _prop.var.etc.showSpNature) { mixin(S_TRACE);
1092			foreach (n, b; _nature) { mixin(S_TRACE);
1093				if (b.getSelection()) { mixin(S_TRACE);
1094					nature = summSkin.natureCoupon(n);
1095					break;
1096				}
1097			}
1098			foreach (chld; _natureComp.getChildren()) { mixin(S_TRACE);
1099				chld.dispose();
1100			}
1101			typeof(_nature) tbl;
1102			_nature = tbl;
1103
1104			bool selected = false;
1105			void sep() { mixin(S_TRACE);
1106				auto sep = new Label(_natureComp, SWT.SEPARATOR | SWT.HORIZONTAL);
1107				auto gd = new GridData(GridData.FILL_HORIZONTAL);
1108				gd.horizontalSpan = 2;
1109				sep.setLayoutData(gd);
1110			}
1111			void put(Nature n) { mixin(S_TRACE);
1112				auto name = summSkin.natureName(n);
1113				auto b = createR(_natureComp, _prop.msgs.nature.get(name, name), (_nature.length + 1) % 2);
1114				_nature[n] = b;
1115				if (!first && nature == summSkin.natureCoupon(n)) { mixin(S_TRACE);
1116					b.setSelection(true);
1117					selected = true;
1118				}
1119			}
1120			foreach (n; NATURE_DEF) { mixin(S_TRACE);
1121				put(n);
1122			}
1123			if (_prop.var.etc.showSpNature) { mixin(S_TRACE);
1124				sep();
1125				foreach (n; NATURE_EXT) { mixin(S_TRACE);
1126					put(n);
1127				}
1128			}
1129			sep();
1130			_natureU = createR(_natureComp, _prop.msgs.natureUnknown, 1);
1131			if (!first && !selected) { mixin(S_TRACE);
1132				_natureU.setSelection(true);
1133				selected = true;
1134			}
1135		}
1136
1137		if (!first && _showSpNature != _prop.var.etc.showSpNature) { mixin(S_TRACE);
1138			_showSpNature = _prop.var.etc.showSpNature;
1139			_natureComp.layout(true);
1140			_natureComp.getParent().layout(true);
1141			_natureComp.getParent().getParent().layout(true);
1142			if (_showSpNature) { mixin(S_TRACE);
1143				if (_natureU.getSelection()) { mixin(S_TRACE);
1144					cp: foreach (i, cp; _couponView.coupons) { mixin(S_TRACE);
1145						if (0 == cp.value) { mixin(S_TRACE);
1146							foreach (n; NATURE_EXT) { mixin(S_TRACE);
1147								if (cp.name == summSkin.natureCoupon(n)) { mixin(S_TRACE);
1148									_nature[n].setSelection(true);
1149									_natureU.setSelection(false);
1150									_couponView.delCoupon(i);
1151									break cp;
1152								}
1153							}
1154						}
1155					}
1156				}
1157			} else { mixin(S_TRACE);
1158				if (_natureU.getSelection() && "" != nature) { mixin(S_TRACE);
1159					_couponView.addCoupon(new Coupon(nature, 0));
1160				}
1161			}
1162		}
1163	}
1164
1165public:
1166	this(Commons comm, Props prop, Shell shell, Summary summ, CastCard card, bool readOnly) { mixin(S_TRACE);
1167		assert (summ !is null);
1168		_id = format("%08X", &this) ~ "-" ~ to!(string)(Clock.currTime());
1169		_comm = comm;
1170		_summ = summ;
1171		_card = card;
1172		_prop = prop;
1173		_readOnly = readOnly ? SWT.READ_ONLY : SWT.NONE;
1174		if (_readOnly) _summSkin = findSkin(_comm, _prop, _summ);
1175		super(prop, shell, _readOnly, false, _card ? .tryFormat(_prop.msgs.dlgTitCast, _card.name) : _prop.msgs.dlgTitNewCast,
1176			_prop.images.casts, true, _prop.var.castCardDlg, true);
1177	}
1178
1179	@property
1180	CastCard card() { mixin(S_TRACE);
1181		return _card;
1182	}
1183
1184	bool openCWXPath(string path, bool shellActivate) { mixin(S_TRACE);
1185		return cpempty(path);
1186	}
1187protected:
1188	override void setup(Composite area) { mixin(S_TRACE);
1189		area.setLayout(windowGridLayout(1));
1190		auto tabf = new CTabFolder(area, SWT.BORDER);
1191		constructBase(tabf);
1192		constructDesc(tabf);
1193		constructHistory(tabf);
1194		constructMakings(tabf);
1195		constructResist(tabf);
1196		constructPhysical(tabf);
1197		constructMental(tabf);
1198		constructEnhance(tabf);
1199		constructStatus(tabf);
1200
1201		_comm.delCast.add(&delCard);
1202		_comm.refScenario.add(&refScenario);
1203		_comm.refSkin.add(&refSkin);
1204		_comm.refCoupons.add(&updateNature);
1205		_comm.refRadarStyle.add(&initPhysical);
1206		_comm.refRadarStyle.add(&initEnhance);
1207		area.addDisposeListener(new Dispose);
1208
1209		// Windows Vista???????????????????????????
1210		scope maxSize = new Point(0, 0);
1211		foreach (tab; tabf.getItems()) { mixin(S_TRACE);
1212			scope size = tab.getControl().computeSize(SWT.DEFAULT, SWT.DEFAULT);
1213			if (maxSize.x < size.x) maxSize.x = size.x;
1214			if (maxSize.y < size.y) maxSize.y = size.y;
1215		}
1216		scope rect = tabf.computeTrim(SWT.DEFAULT, SWT.DEFAULT, maxSize.x, maxSize.y);
1217		auto gd = new GridData(GridData.FILL_BOTH);
1218		gd.widthHint = rect.width;
1219		gd.heightHint = rect.height;
1220		tabf.setLayoutData(gd);
1221
1222		refCard(_card);
1223	}
1224	private void refCard(CastCard card) { mixin(S_TRACE);
1225		if (_card && _card !is card) return;
1226		ignoreMod = true;
1227		scope (exit) ignoreMod = false;
1228		auto skin = summSkin;
1229		if (_card) { mixin(S_TRACE);
1230			_imgPath.image = _card.path;
1231			if (_race) _race.select(0);
1232			_desc.setText(_card.desc);
1233			_name.setText(_card.name);
1234			_level.setSelection(_card.level);
1235			_lifeMax.setSelection(_card.lifeMax);
1236			bool sex = false, period = false, nature = false;
1237			scope makings = new HashSet!(Makings);
1238			Coupon[] coupons;
1239			cp: foreach (c; _card.coupons) { mixin(S_TRACE);
1240				foreach (s, b; _sex) { mixin(S_TRACE);
1241					if (c.name == skin.sexCoupon(s)) { mixin(S_TRACE);
1242						if (!sex) b.setSelection(true);
1243						sex = true;
1244						continue cp;
1245					}
1246				}
1247				foreach (per, b; _period) { mixin(S_TRACE);
1248					if (c.name == skin.periodCoupon(per)) { mixin(S_TRACE);
1249						if (!period) b.setSelection(true);
1250						period = true;
1251						continue cp;
1252					}
1253				}
1254				foreach (nat, b; _nature) { mixin(S_TRACE);
1255					if (c.name == skin.natureCoupon(nat)) { mixin(S_TRACE);
1256						if (!nature) b.setSelection(true);
1257						nature = true;
1258						continue cp;
1259					}
1260				}
1261				foreach (m, b; _makings) { mixin(S_TRACE);
1262					if (c.name == skin.makingsCoupon(m)) { mixin(S_TRACE);
1263						if (!makings.contains(m)) b.setSelection(true);
1264						makings.add(m);
1265						continue cp;
1266					}
1267				}
1268				if (_race) { mixin(S_TRACE);
1269					foreach (i, r; summSkin.races) { mixin(S_TRACE);
1270						if (c.name == _prop.sys.raceCoupon(r.name)) { mixin(S_TRACE);
1271							_race.select(i + 1);
1272							raceToolTip();
1273							continue cp;
1274						}
1275					}
1276				}
1277				coupons ~= new Coupon(c);
1278			}
1279			_couponView.coupons = coupons;
1280			if (!sex) _sexU.setSelection(true);
1281			if (!period) _periodU.setSelection(true);
1282			if (!nature) _natureU.setSelection(true);
1283			_resW.setSelection(_card.weaponResist);
1284			_resM.setSelection(_card.magicResist);
1285			_undead.setSelection(_card.undead);
1286			_automaton.setSelection(_card.automaton);
1287			_unholy.setSelection(_card.unholy);
1288			_constructure.setSelection(_card.constructure);
1289			foreach (e, radio; _res) { mixin(S_TRACE);
1290				radio.setSelection(_card.resist(e));
1291			}
1292			foreach (e, radio; _weak) { mixin(S_TRACE);
1293				radio.setSelection(_card.weakness(e));
1294			}
1295			foreach (phy, i; _phyTbl) { mixin(S_TRACE);
1296				if (_phyR) { mixin(S_TRACE);
1297					_phyR.setValue(i, _card.physical(phy));
1298				} else { mixin(S_TRACE);
1299					_phyS.setValue(i, _card.physical(phy));
1300				}
1301			}
1302			foreach (mtl, scale; _mtl) { mixin(S_TRACE);
1303				scale.setSelection(_prop.var.etc.mentalMax + _card.mental(mtl));
1304			}
1305			foreach (enh, i; _enhTbl) { mixin(S_TRACE);
1306				if (_enhR) { mixin(S_TRACE);
1307					_enhR.setValue(i, _card.defaultEnhance(enh));
1308				} else { mixin(S_TRACE);
1309					_enhS.setValue(i, _card.defaultEnhance(enh));
1310				}
1311			}
1312
1313			_life.setSelection(_card.life);
1314			_lifeUseMax.setSelection(_card.life == _card.lifeMax);
1315			foreach (enh, spn; _liveEnh) { mixin(S_TRACE);
1316				spn.setSelection(_card.enhance(enh));
1317			}
1318			foreach (enh, spn; _enhRound) { mixin(S_TRACE);
1319				spn.setSelection(_card.enhanceRound(enh));
1320			}
1321			_paralyze.setSelection(_card.paralyze);
1322			_poison.setSelection(_card.poison);
1323			_bind.setSelection(_card.bindRound);
1324			_silence.setSelection(_card.silenceRound);
1325			_faceUp.setSelection(_card.faceUpRound);
1326			_antiMagic.setSelection(_card.antiMagicRound);
1327			_mtlyRound.setSelection(_card.mentalityRound);
1328			changeLiveEnhance();
1329			changeMentality();
1330			changeLifeUseMax();
1331		} else { mixin(S_TRACE);
1332			_imgPath.image = "";
1333			if (_race) _race.select(0);
1334			_sexU.setSelection(true);
1335			_periodU.setSelection(true);
1336			_natureU.setSelection(true);
1337			int[] phys;
1338			phys.length = PHYSICALS.length;
1339			phys[] = _prop.looks.physicalNormal;
1340			if (_phyR) { mixin(S_TRACE);
1341				_phyR.setValues(phys);
1342			} else { mixin(S_TRACE);
1343				_phyS.setValues(phys);
1344			}
1345			foreach (radio; _mtl) { mixin(S_TRACE);
1346				radio.setSelection(_prop.var.etc.mentalMax);
1347			}
1348			int[] bonus;
1349			bonus.length = ENHANCE.length;
1350			bonus[] = 0;
1351			if (_enhR) { mixin(S_TRACE);
1352				_enhR.setValues(bonus);
1353			} else { mixin(S_TRACE);
1354				_enhS.setValues(bonus);
1355			}
1356
1357			resetLiveStatus();
1358		}
1359		setMaxLife();
1360		modPhysical();
1361	}
1362
1363	private Coupon createCoupon(E)(Button[E] radios, string delegate(E) coupon) { mixin(S_TRACE);
1364		foreach (e, radio; radios) { mixin(S_TRACE);
1365			if (radio.getSelection()) { mixin(S_TRACE);
1366				return new Coupon(coupon(e), 0);
1367			}
1368		}
1369		return null;
1370	}
1371	override bool apply() { mixin(S_TRACE);
1372		if (_card) { mixin(S_TRACE);
1373			_card.path = _imgPath.image;
1374			_card.desc = _desc.getRRText();
1375			_card.name = _name.getText();
1376			_card.level = _level.getSelection();
1377			_card.lifeMax = _lifeMax.getSelection();
1378			_card.life = _lifeMax.getSelection();
1379		} else { mixin(S_TRACE);
1380			_card = new CastCard(_summ.newId!(CastCard), _name.getText(), _imgPath.image,
1381				_desc.getRRText(), _level.getSelection(), _lifeMax.getSelection());
1382		}
1383		auto skin = summSkin;
1384		string legacyName = skin.legacyName;
1385		alias contains!("a.name == b.name", Coupon, Coupon) cContains;
1386		auto tblCoupons = _couponView.coupons;
1387		Coupon[] cs;
1388		auto sex = createCoupon!(Sex)(_sex, &skin.sexCoupon);
1389		if (sex && !cContains(tblCoupons, sex)) cs ~= sex;
1390		auto race = selectedRace;
1391		if (race) { mixin(S_TRACE);
1392			auto rc = new Coupon(_prop.sys.raceCoupon(race.name), 0);
1393			if (!cContains(tblCoupons, rc)) cs ~= rc;
1394		}
1395		auto period = createCoupon!(Period)(_period, &skin.periodCoupon);
1396		if (period && !cContains(tblCoupons, period)) cs ~= period;
1397		auto nature = createCoupon!(Nature)(_nature, &skin.natureCoupon);
1398		if (nature && !cContains(tblCoupons, nature)) cs ~= nature;
1399		foreach (m, radio; _makings) { mixin(S_TRACE);
1400			if (radio.getSelection()) { mixin(S_TRACE);
1401				auto mc = new Coupon(skin.makingsCoupon(m), 0);
1402				if (!cContains(tblCoupons, mc)) cs ~= mc;
1403			}
1404		}
1405		cs ~= tblCoupons;
1406		_card.coupons = cs;
1407		_card.weaponResist = _resW.getSelection();
1408		_card.magicResist = _resM.getSelection();
1409		_card.undead = _undead.getSelection();
1410		_card.automaton = _automaton.getSelection();
1411		_card.unholy = _unholy.getSelection();
1412		_card.constructure = _constructure.getSelection();
1413		foreach (e, radio; _res) { mixin(S_TRACE);
1414			_card.resist(e, radio.getSelection());
1415		}
1416		foreach (e, radio; _weak) { mixin(S_TRACE);
1417			_card.weakness(e, radio.getSelection());
1418		}
1419		foreach (phy, i; _phyTbl) { mixin(S_TRACE);
1420			if (_phyR) { mixin(S_TRACE);
1421				_card.physical(phy, _phyR.getValue(i));
1422			} else { mixin(S_TRACE);
1423				_card.physical(phy, _phyS.getValue(i));
1424			}
1425		}
1426		foreach (mtl, scale; _mtl) { mixin(S_TRACE);
1427			_card.mental(mtl, cast(int) scale.getSelection() - _prop.var.etc.mentalMax);
1428		}
1429		foreach (enh, i; _enhTbl) { mixin(S_TRACE);
1430			if (_enhR) { mixin(S_TRACE);
1431				_card.defaultEnhance(enh, _enhR.getValue(i));
1432			} else { mixin(S_TRACE);
1433				_card.defaultEnhance(enh, _enhS.getValue(i));
1434			}
1435		}
1436
1437		_card.life = _lifeUseMax.getSelection() ? _card.lifeMax : _life.getSelection();
1438		foreach (enh, spn; _liveEnh) { mixin(S_TRACE);
1439			if (_enhRound[enh].getSelection() > 0) { mixin(S_TRACE);
1440				_card.enhance(enh, spn.getSelection());
1441			} else { mixin(S_TRACE);
1442				_card.enhance(enh, 0);
1443			}
1444		}
1445		foreach (enh, spn; _enhRound) { mixin(S_TRACE);
1446			if (_card.enhance(enh) != 0) { mixin(S_TRACE);
1447				_card.enhanceRound(enh, spn.getSelection());
1448			} else { mixin(S_TRACE);
1449				_card.enhanceRound(enh, 0);
1450			}
1451		}
1452		_card.paralyze = _paralyze.getSelection();
1453		_card.poison = _poison.getSelection();
1454		_card.bindRound = _bind.getSelection();
1455		_card.silenceRound = _silence.getSelection();
1456		_card.faceUpRound = _faceUp.getSelection();
1457		_card.antiMagicRound = _antiMagic.getSelection();
1458		_card.mentality = _mtlyRound.getSelection() == 0
1459			? Mentality.NORMAL : _mtlyTbl[_mtly.getSelectionIndex()];
1460		_card.mentalityRound = _card.mentality == Mentality.NORMAL
1461			? 0 : _mtlyRound.getSelection();
1462
1463		_comm.refCoupons.call();
1464		getShell().setText(.tryFormat(_prop.msgs.dlgTitCast, _card.name));
1465		return true;
1466	}
1467}