OSDN Git Service

add amulet search with fixed seed2
[amulettoolsmh4/main.git] / view / notebookamuletview.py
1 # -*- coding: utf-8 -*-
2
3 # GUIのメインフレームにおけるお守り検索Notebookのview
4 # 2013/12/15 written by kei9
5 import wx
6 from wx import xrc
7 import wx.grid
8
9 import constnumbers
10
11 class NoteBookAmuletView():
12     u""" メインのフレームのお守り検索タブ """
13     def __init__(self, frame):
14         self.frame = frame
15         self._init_view()
16         self._init_event()
17         self.update_filter_radio()
18         self._last_search_type = None
19
20     def _init_view(self):
21         # initialize view
22
23         # button
24         self.button_search = xrc.XRCCTRL(self.frame, "ButtonAmuletSearchSearch")
25         self.button_clear = xrc.XRCCTRL(self.frame, "ButtonAmuletSearchClear")
26         self.button_simulate = xrc.XRCCTRL(self.frame, "ButtonAmuletToSimulator")
27         self.ID_BUTTON_SEARCH = xrc.XRCID("ButtonAmuletSearchSearch")
28         self.ID_BUTTON_CLEAR = xrc.XRCID("ButtonAmuletSearchClear")
29         self.ID_BUTTON_SIMULATE = xrc.XRCID("ButtonAmuletToSimulator")
30
31         # radio button
32         self.radiobox_amulet = xrc.XRCCTRL(self.frame, "RadioBoxAmulet")
33         self.radiobox_search_type = xrc.XRCCTRL(self.frame, "RadioBoxSearchType")
34         self.radiobox_filter = xrc.XRCCTRL(self.frame, "RadioBoxFilter")
35
36         # seeds grid
37         self.grid_seeds = xrc.XRCCTRL(self.frame, "GridAmuletSeeds")
38         self.grid_seeds.CreateGrid(1, constnumbers.NUM_AMULET_SEEDS_GRID_COL)
39         self.grid_seeds.SetColLabelValue(0, constnumbers.LABEL_FORMAT_AMULET_SEEDS_GRID_COL1)
40         self.grid_seeds.SetColLabelValue(1, constnumbers.LABEL_FORMAT_AMULET_SEEDS_GRID_COL2)
41         self.grid_seeds.DisableDragGridSize()
42         self.grid_seeds.EnableEditing(False)
43         self.grid_seeds.SetRowLabelSize(30)
44         self.grid_seeds.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
45
46         # spin ctrl
47         self.spin_ctrl_skill1_val = xrc.XRCCTRL(self.frame, "SpinCtrlAmuletSearchSkill1Value")
48         self.spin_ctrl_skill2_val = xrc.XRCCTRL(self.frame, "SpinCtrlAmuletSearchSkill2Value")
49         self.spin_ctrl_slot_num = xrc.XRCCTRL(self.frame, "SpinCtrlAmuletSearchSlotNumber")
50         self.ID_SPIN_CTRL_SKILL1_VAL = xrc.XRCID("SpinCtrlAmuletSearchSkill1Value")
51         self.ID_SPIN_CTRL_SKILL2_VAL = xrc.XRCID("SpinCtrlAmuletSearchSkill2Value")
52
53         # combobox
54         self.combo_box_skill1 = xrc.XRCCTRL(self.frame, "ComboBoxAmuletSearchSkill1")
55         self.combo_box_skill2 = xrc.XRCCTRL(self.frame, "ComboBoxAmuletSearchSkill2")
56         self.ID_COMBO_BOX_SKILL1 = xrc.XRCID("ComboBoxAmuletSearchSkill1")
57         self.ID_COMBO_BOX_SKILL2 = xrc.XRCID("ComboBoxAmuletSearchSkill2")
58
59         # text ctrl
60         self.text_ctrl_result = xrc.XRCCTRL(self.frame, "TextCtrlAmuletSearchResult")
61         self.text_ctrl_seed2 = xrc.XRCCTRL(self.frame, "TextCtrlFixedSeed2")
62
63         # set min & max of slot
64         self.set_slot_minmax(constnumbers.SLOT_MIN, constnumbers.SLOT_MAX)
65
66     def _init_event(self):
67         # initialize event
68         self.grid_seeds.Bind(wx.EVT_SIZE, self.OnSeedGridSizeChanged)
69         self.combo_box_skill1.Bind(wx.EVT_COMBOBOX, self.OnComboSkill1Changed)
70         self.combo_box_skill2.Bind(wx.EVT_COMBOBOX, self.OnComboSkill2Changed)
71         self.radiobox_amulet.Bind(wx.EVT_RADIOBOX, self.OnRadioAmuletChanged)
72         self.radiobox_search_type.Bind(wx.EVT_RADIOBOX, self.OnRadioSearchTypeChanged)
73         self.radiobox_filter.Bind(wx.EVT_RADIOBOX, self.OnRadioFilterChanged)
74
75     def OnSeedGridSizeChanged(self, event):
76         u""" SeedGridサイズの変更時 """
77         width, height = self.grid_seeds.GetParent().GetSize()
78         each_width = (width-40) / (constnumbers.NUM_AMULET_SEEDS_GRID_COL) # consider margin size
79         #self.grid_seeds.SetRowLabelValue(0, u"")
80         for col in range(constnumbers.NUM_AMULET_SEEDS_GRID_COL):
81             self.grid_seeds.SetColSize(col, each_width)
82
83     def OnComboSkill1Changed(self, event):
84         u""" スキル1のコンボボックスの変更時 """
85         self.update_skill_minmax(1)
86
87     def OnComboSkill2Changed(self, event):
88         u""" スキル2のコンボボックスの変更時 """
89         self.update_skill_minmax(2)
90
91     def OnRadioAmuletChanged(self, event):
92         u""" お守り選択のラジオボタン変更時 """
93         self.update_skill_names()
94         self.update_skill_minmax()
95
96     def OnRadioSearchTypeChanged(self, event):
97         u""" お守り選択のラジオボタン変更時 """
98         search_type = self.get_selected_search_type()
99         if search_type == constnumbers.SEARCH_TYPE_FIXED_SEED2:
100             self.text_ctrl_seed2.Enable()
101         else:
102             self.text_ctrl_seed2.Disable()
103
104     def OnRadioFilterChanged(self, event):
105         u""" 結果表示のフィルターラジオボックスの変更時 """
106         if self._last_search_type == None:
107             pass
108         elif self._last_search_type == constnumbers.SEARCH_TYPE_SEED2:
109             self._set_items_dict_only_seed2()
110         elif self._last_search_type == constnumbers.SEARCH_TYPE_FIXED_SEED2:
111             self._set_items_dict_fixed_seed2()
112         else:
113             raise NotImplementedError("irregular radio button selected")
114
115     def bind_radiobox_search_type(self, event_func, evt=wx.EVT_RADIOBOX):
116         u""" 判定値の種類のラジオボタンが押された時のイベントをセットする """
117         self.radiobox_search_type.Bind(evt, event_func)
118
119     def bind_button_search(self, event_func, evt=wx.EVT_BUTTON):
120         u""" 検索ボタンが押された時のイベントをセットする """
121         self.button_search.Bind(evt, event_func)
122
123     def bind_button_clear(self, event_func, evt=wx.EVT_BUTTON):
124         u""" クリアボタンが押された時のイベントをセットする """
125         self.button_clear.Bind(evt, event_func)
126
127     def bind_button_simulate(self, event_func, evt=wx.EVT_BUTTON):
128         u""" シミュレーター移動ボタンが押された時のイベントをセットする """
129         self.button_simulate.Bind(evt, event_func)
130
131     def set_skillminmax_dict(self, skill_names, amulet_names, minmax_dict):
132         u"""スキル名のリスト、お守り名のリスト、
133         そのお守りに対応する第1,2スキルの最大最小の辞書をセットする
134         {amulet_name:({skill1_name:(min1,max1)}, {skill2_name:(min2,max2)})}
135         """
136         self._skill_names = skill_names
137         self._amulet_names = amulet_names
138         self._minmax_dict = minmax_dict
139         self.set_selected_amulet(constnumbers.NAME_AMULET1)
140         self.update_skill_names()
141         self.update_skill_minmax()
142
143     def set_skillnames_ordered(self, skillnames):
144         u""" 順番に並べられたスキル名のシーケンスをセットする """
145         self._skillnames = skillnames
146
147     def update_skill_names(self):
148         u""" 選択されたお守り名に応じてスキル名のリストを更新する """
149         amu_name = self.get_selected_amulet()
150         skill1_minmax, skill2_minmax = self._minmax_dict[amu_name]
151         self.combo_box_skill1.SetItems([x for x in self._skill_names if x in skill1_minmax])
152         self.combo_box_skill2.SetItems([constnumbers.VAL_NO_SKILL] + 
153                 [x for x in self._skill_names if x in skill2_minmax])
154         self.combo_box_skill1.SetSelection(0)
155         self.combo_box_skill2.SetSelection(0)
156
157     def update_skill_minmax(self, index=None):
158         u""" 選択されたスキル名に応じて値の範囲を設定する """
159         amu_name = self.get_selected_amulet()
160         skill1_minmax, skill2_minmax = self._minmax_dict[amu_name]
161
162         if index is None or index == 1:
163             skill1_name = self.combo_box_skill1.GetStringSelection()
164             if skill1_name in skill1_minmax:
165                 min1, max1 = skill1_minmax[skill1_name]
166                 self.spin_ctrl_skill1_val.SetRange(min1, max1)
167             else:
168                 self.spin_ctrl_skill1_val.SetRange(0, 0)
169
170         if index is None or index == 2:
171             skill2_name = self.combo_box_skill2.GetStringSelection()
172             if skill2_name in skill2_minmax:
173                 min2, max2 = skill2_minmax[skill2_name]
174                 self.spin_ctrl_skill2_val.SetRange(min2, max2)
175             else:
176                 self.spin_ctrl_skill2_val.SetRange(0, 0)
177
178     def update_filter_radio(self):
179         u""" 検索方式に応じて結果表示のフィルターを変える """
180         search_type = self.get_selected_search_type()
181         if search_type == constnumbers.SEARCH_TYPE_SEED2:
182             self.radiobox_filter.SetItemLabel(0, constnumbers.SEARCH_TYPE_SEED2_FILTER1)
183             self.radiobox_filter.SetItemLabel(1, constnumbers.SEARCH_TYPE_SEED2_FILTER2)
184             self.radiobox_filter.SetItemLabel(2, constnumbers.SEARCH_TYPE_SEED2_FILTER3)
185             self.grid_seeds.SetColLabelValue(0, constnumbers.SEARCH_TYPE_SEED2_COL1)
186             self.grid_seeds.SetColLabelValue(1, constnumbers.SEARCH_TYPE_SEED2_COL2)
187         elif search_type == constnumbers.SEARCH_TYPE_FIXED_SEED2:
188             self.radiobox_filter.SetItemLabel(0, constnumbers.SEARCH_TYPE_FIXED_SEED2_FILTER1)
189             self.radiobox_filter.SetItemLabel(1, constnumbers.SEARCH_TYPE_FIXED_SEED2_FILTER2)
190             self.radiobox_filter.SetItemLabel(2, constnumbers.SEARCH_TYPE_FIXED_SEED2_FILTER3)
191             self.grid_seeds.SetColLabelValue(0, constnumbers.SEARCH_TYPE_FIXED_SEED2_COL1)
192             self.grid_seeds.SetColLabelValue(1, constnumbers.SEARCH_TYPE_FIXED_SEED2_COL2)
193         else:
194             raise NotImplementedError("irregular radio button selected")
195
196     def set_slot_minmax(self, slot_min, slot_max):
197         u""" スロットの最大値と最小値をセットする """
198         self.spin_ctrl_slot_num.SetRange(slot_min, slot_max)
199
200     def get_skill_values(self):
201         u""" 第1,2スキルの値を得る 
202         return (skill1_val, skill2_val)"""
203         skill1_val = self.spin_ctrl_skill1_val.GetValue()
204         skill2_val = self.spin_ctrl_skill2_val.GetValue()
205         return (skill1_val, skill2_val)
206
207     def get_slot_value(self):
208         u""" スロットの値を得る """
209         return self.spin_ctrl_slot_num.GetValue()
210
211     def clear_input_values(self):
212         u""" 入力された値を初期化する """
213         self.combo_box_skill1.SetSelection(0)
214         self.combo_box_skill2.SetSelection(0)
215         self.spin_ctrl_skill1_val.SetValue(1)
216         self.spin_ctrl_skill2_val.SetValue(0)
217         self.spin_ctrl_slot_num.SetValue(1)
218         self.text_ctrl_seed2.SetValue(u"")
219         self.text_ctrl_result.SetValue(u"")
220
221     def get_fixed_seed2(self):
222         u""" seed2固定検索時のSeed2を返す """
223         seed2 = self.text_ctrl_seed2.GetValue()
224         if seed2.isdigit():
225             return int(seed2)
226         else:
227             return None
228
229     def set_selected_amulet(self, value, amulet_name=constnumbers.NAME_AMULET1):
230         u""" ラジオボタンの値をセットする 
231             arg: (value, amulet_name)
232         """
233         if amulet_name == constnumbers.NAME_AMULET1:
234             idx = 0
235         elif amulet_name == constnumbers.NAME_AMULET2:
236             idx = 1
237         elif amulet_name == constnumbers.NAME_AMULET3:
238             idx = 2
239         self.radiobox_amulet.SetSelection(idx)
240
241     def get_selected_amulet(self):
242         u""" 選択されているお守り名を得る 
243             return: (NAME_OF_AMULET)
244         """
245         idx = self.radiobox_amulet.GetSelection()
246         if idx == 0:
247             return constnumbers.NAME_AMULET1
248         elif idx == 1:
249             return constnumbers.NAME_AMULET2
250         elif idx == 2:
251             return constnumbers.NAME_AMULET3
252         else:
253             raise NotImplementedError("irregular radio button selected")
254
255     def get_selected_search_type(self):
256         u""" 選択されているラジオボタンの検索種類IDを得る
257             return: (THRESHOLD_TYPE_ID)
258         """
259         idx = self.radiobox_search_type.GetSelection()
260         if idx == 0:
261             return constnumbers.SEARCH_TYPE_SEED2
262         elif idx == 1:
263             return constnumbers.SEARCH_TYPE_FIXED_SEED2
264         elif idx == 2:
265             return constnumbers.SEARCH_TYPE_SEED1_SEED2
266         else:
267             raise NotImplementedError("irregular radio button selected")
268
269     def get_selected_tenun_type(self):
270         u""" 固定Seed2における天運の種類を返す。判別できない場合はNone """
271         if self._last_search_type == constnumbers.SEARCH_TYPE_FIXED_SEED2:
272             filter_str = self.radiobox_filter.GetStringSelection()
273             if filter_str == constnumbers.SEARCH_TYPE_FIXED_SEED2_FILTER1:
274                 return constnumbers.KEY_TENUN888
275             elif filter_str == constnumbers.SEARCH_TYPE_FIXED_SEED2_FILTER2:
276                 return constnumbers.KEY_TENUN555
277             elif filter_str == constnumbers.SEARCH_TYPE_FIXED_SEED2_FILTER3:
278                 return constnumbers.KEY_TENUN888
279         else:
280             return None
281
282     def get_skill_names(self):
283         u""" skill1, skill2で選択されているスキル名を返す
284             return (skill1_name, skill2_name)"""
285         skill1_name = self.combo_box_skill1.GetStringSelection()
286         skill2_name = self.combo_box_skill2.GetStringSelection()
287         return (skill1_name, skill2_name)
288
289     def set_skill_names(self, skill1_names, skill2_names):
290         u""" スキル1、スキル2のコンボボックスの一覧をセットする """
291         self.combo_box_skill1.SetItems(skill1_names)
292         self.combo_box_skill2.SetItems(skill2_names)
293
294     def set_simualte_button_enable(self, value):
295         u""" 対応スキル検索ボタンの有効・無効の切り替え """
296         if value is True:
297             self.button_simulate.Enable()
298         else:
299             self.button_simulate.Disable()
300
301     def set_result(self, value):
302         u""" 結果表示用のTextCtrlに値をセットする """
303         self.text_ctrl_result.SetValue(value)
304
305     def set_result_only_seed2(self, suff_val, threshold, th1_seed2s, th2_seed2s):
306         u""" Seed2のみからの検索結果表示用に値をセットする """
307         self.update_filter_radio()
308         seed2s = th1_seed2s | th2_seed2s
309         self.text_ctrl_result.SetValue(u"""※簡易検索のため、不正確な場合があります
310 充足値: {0}, 必要な判定値: {1}
311 {1}以上の判定値1を持つSeed2: {2}
312 {1}以上の判定値2を持つSeed2: {3}
313 {1}以上の判定値を持つSeed2: {4}""".format(
314             suff_val, threshold, len(th1_seed2s), len(th2_seed2s), len(seed2s)))
315         self._last_search_type = constnumbers.SEARCH_TYPE_SEED2
316         self._last_values = (suff_val, threshold, th1_seed2s, th2_seed2s)
317         self._set_items_dict_only_seed2()
318
319     def _set_items_dict_only_seed2(self):
320         u""" Seed2のみからの検索時結果をフィルターに応じて表示 """
321         if self._last_search_type == constnumbers.SEARCH_TYPE_SEED2:
322             filter_str = self.radiobox_filter.GetStringSelection()
323             if filter_str == constnumbers.SEARCH_TYPE_SEED2_FILTER1:
324                 th1_include, th2_include = True, True
325             elif filter_str == constnumbers.SEARCH_TYPE_SEED2_FILTER2:
326                 th1_include, th2_include = True, False
327             elif filter_str == constnumbers.SEARCH_TYPE_SEED2_FILTER3:
328                 th1_include, th2_include = False, True
329
330             suff_val, threshold, th1_seed2s, th2_seed2s = self._last_values
331             seed2s = th1_seed2s | th2_seed2s
332             items_dict = {}
333             for seed2 in seed2s:
334                 texts = []
335                 is_include = False
336                 if seed2 in th1_seed2s:
337                     texts.append(u"判定値1")
338                     if th1_include:
339                         is_include = True
340                 if seed2 in th2_seed2s:
341                     texts.append(u"判定値2")
342                     if th2_include:
343                         is_include = True
344                 if is_include:
345                     texts = u", ".join(texts)
346                     texts = u"Seed2({0})".format(texts) if len(texts) > 0 else texts
347                     items_dict[seed2] = texts
348             self.set_grid_seeds_items(items_dict)
349
350     def set_result_fixed_seed2(self, suff_val, threshold, seed2, seed1s_555, seed1s_888):
351         u""" 固定Seed2からの検索結果表示用に値をセットする """
352         self.update_filter_radio()
353         seed1s = seed1s_555 | seed1s_888
354         self.text_ctrl_result.SetValue(u"""Seed2:\t{0}
355 充足値: {1}, 必要な判定値: {2}
356 天運555におけるSeed1:\t{3}
357 天運888におけるSeed1:\t{4}
358 Seed1の合計:\t{5}""".format(seed2, suff_val, threshold, len(seed1s_555), len(seed1s_888), len(seed1s)))
359
360         self._last_search_type = constnumbers.SEARCH_TYPE_FIXED_SEED2
361         self._last_values = (suff_val, threshold, seed2, seed1s_555, seed1s_888)
362         self._set_items_dict_fixed_seed2()
363
364     def _set_items_dict_fixed_seed2(self):
365         u""" 固定Seed2からの検索時結果をフィルターに応じて表示 """
366         if self._last_search_type == constnumbers.SEARCH_TYPE_FIXED_SEED2:
367             filter_str = self.radiobox_filter.GetStringSelection()
368             if filter_str == constnumbers.SEARCH_TYPE_FIXED_SEED2_FILTER1:
369                 include_555, include_888 = True, True
370             elif filter_str == constnumbers.SEARCH_TYPE_FIXED_SEED2_FILTER2:
371                 include_555, include_888 = True, False
372             elif filter_str == constnumbers.SEARCH_TYPE_FIXED_SEED2_FILTER3:
373                 include_555, include_888 = False, True
374
375             items_dict = {}
376             suff_val, threshold, seed2, seed1s_555, seed1s_888 = self._last_values
377             seed1s = seed1s_555 | seed1s_888
378             for seed1 in seed1s:
379                 texts = []
380                 is_include = False
381                 if seed1 in seed1s_555:
382                     texts.append(u"天運555")
383                     if include_555:
384                         is_include = True
385                 if seed1 in seed1s_888:
386                     texts.append(u"天運888")
387                     if include_888:
388                         is_include = True
389                 if is_include:
390                     texts = u", ".join(texts)
391                     texts = u"Seed1({0})".format(texts) if len(texts) > 0 else texts
392                     items_dict[seed1] = texts
393             self.set_grid_seeds_items(items_dict)
394
395     def set_result_seeds(self, suff_val, result_dict):
396         u""" 全検索の結果を表示する。
397         Seed2から各天運のSeed1の集合の辞書を引数とする。
398         result_dict={seed2:(seed1s_555, seed1s_888)}"""
399         u"""
400         self.text_ctrl_result.SetValue(u"充足値: {0} Seed2の総数:\t{1}".format(suff_val, len(result_dict)))
401         items_dict = {}
402         for seed2, (seed1s_555, seed1s_888) in result_dict.items():
403             seed1s = seed1s_555 | seed1s_888
404             for seed1 in seed1s:
405                 texts = []
406                 if seed1 in seed1s_555:
407                     texts.append(u"天運555")
408                 if seed1 in seed1s_888:
409                     texts.append(u"天運888")
410                 texts = u", ".join(texts)
411                 texts = u"Seed1({0})".format(texts) if len(texts) > 0 else texts
412                 items_dict[(seed1, seed2)] = texts
413         self.set_grid_seeds_items(items_dict)
414         """
415         raise NotImplementedError(u"give up to implement all search because of ttoo heavy and long calc")
416
417     def set_grid_seeds_items(self, items_dict):
418         u""" Seed一覧のGridに値をセットする。
419         引数はSeed -> 文字列の辞書とする。
420         Noneが与えられた時はClearする"""
421         if items_dict is not None and len(items_dict) > 0:
422             row_num = len(items_dict)
423             diff = row_num - self.grid_seeds.GetNumberRows()
424             if diff > 0:
425                 self.grid_seeds.AppendRows(diff, False)
426             elif diff < 0:
427                 self.grid_seeds.DeleteRows(0, -diff, False)
428
429             for row, seed in enumerate(sorted(items_dict.keys())):
430                 #self.grid_seeds.SetRowLabelValue(row, u"")
431                 type_str = items_dict[seed]
432                 self.grid_seeds.SetCellValue(row, 0, u"{0}".format(seed))
433                 self.grid_seeds.SetCellValue(row, 1, type_str)
434             self.set_simualte_button_enable(True)
435         else:
436             self.clear_grid_seeds()
437             self.set_simualte_button_enable(False)
438
439     def get_selected_seeds(self):
440         u""" Seed一覧のGridの選択された(Seed1,Seed2)の値を得る。"""
441         rows = [x for x in self.grid_seeds.GetSelectedRows()]
442         if len(rows) > 0:
443             if self._last_search_type == constnumbers.SEARCH_TYPE_FIXED_SEED2:
444                 seed1 = int(self.grid_seeds.GetCellValue(rows[0], 0))
445                 seed2 = self._last_values[2]
446                 return seed1, seed2
447             elif self._last_search_type == constnumbers.SEARCH_TYPE_SEED2:
448                 seed1 = None
449                 seed2 = int(self.grid_seeds.GetCellValue(rows[0], 0))
450                 return seed1, seed2
451             else:
452                 return None
453         else:
454             return None
455
456     def set_grid_seeds_selected_idx(self, idx):
457         u""" Seed一覧のGridの選択された行を選択状態にする。"""
458         if idx >= 0 and idx < self.grid_seeds.GetNumberRows():
459             self.grid_seeds.MakeCellVisible(idx, 0)
460             self.grid_seeds.SelectRow(idx)
461
462     def clear_grid_seeds(self):
463         u""" Seed一覧のGridから値をClearする"""
464         for row in range(self.grid_seeds.GetNumberRows()):
465             self.grid_seeds.SetRowLabelValue(row, u"")
466             for col in range(self.grid_seeds.GetNumberCols()):
467                 self.grid_seeds.SetCellValue(row, col, u"")
468         self.grid_seeds.ClearSelection()
469         self.set_simualte_button_enable(False)
470         self._last_search_type = None
471         self._last_valuse = None
472
473     def clear_grid(self):
474         u"""Gridの値をクリアする"""
475         self.clear_grid_seeds()