Coverage for Aux_Hud.py: 0%

249 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-09-27 18:50 +0000

1#!/usr/bin/env python 

2# -*- coding: utf-8 -*- 

3"""Aux_Hud.py 

4 

5Simple HUD display for FreePokerTools/fpdb HUD. 

6""" 

7 

8# import L10n 

9# _ = L10n.get_translation() 

10# Copyright 2011-2012, Ray E. Barker 

11#  

12# This program is free software; you can redistribute it and/or modify 

13# it under the terms of the GNU General Public License as published by 

14# the Free Software Foundation; either version 2 of the License, or 

15# (at your option) any later version. 

16#  

17# This program is distributed in the hope that it will be useful, 

18# but WITHOUT ANY WARRANTY; without even the implied warranty of 

19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

20# GNU General Public License for more details. 

21#  

22# You should have received a copy of the GNU General Public License 

23# along with this program; if not, write to the Free Software 

24# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 

25 

26######################################################################## 

27 

28# to do 

29 

30# Standard Library modules 

31import os 

32import logging 

33# logging has been set up in fpdb.py or HUD_main.py, use their settings: 

34log = logging.getLogger("hud") 

35from functools import partial 

36 

37from PyQt5.QtGui import QCursor, QFont, QPixmap 

38from PyQt5.QtCore import pyqtSignal, Qt 

39from PyQt5.QtWidgets import (QComboBox, QGridLayout, QHBoxLayout, 

40 QLabel, QPushButton, QSpinBox, 

41 QVBoxLayout, QWidget) 

42 

43# FreePokerTools modules 

44import Aux_Base 

45import Stats 

46import Popup 

47import Configuration 

48 

49 

50class Simple_HUD(Aux_Base.Aux_Seats): 

51 """A simple HUD class based on the Aux_Window interface.""" 

52 

53 def __init__(self, hud, config, aux_params): 

54 # Save everything you need to know about the hud as attrs. 

55 # That way a subclass doesn't have to grab them. 

56 # Also, the subclass can override any of these attributes 

57 super(Simple_HUD, self).__init__(hud, config, aux_params) 

58 self.poker_game = self.hud.poker_game 

59 self.site_params = self.hud.site_parameters 

60 self.aux_params = aux_params 

61 self.game_params = self.hud.supported_games_parameters["game_stat_set"] 

62 self.max = self.hud.max 

63 self.nrows = self.game_params.rows 

64 self.ncols = self.game_params.cols 

65 self.xpad = self.game_params.xpad 

66 self.ypad = self.game_params.ypad 

67 self.xshift = self.site_params['hud_menu_xshift'] 

68 self.yshift = self.site_params['hud_menu_yshift'] 

69 self.fgcolor = self.aux_params["fgcolor"] 

70 self.bgcolor = self.aux_params["bgcolor"] 

71 self.opacity = self.aux_params["opacity"] 

72 self.font = QFont(self.aux_params["font"], int(self.aux_params["font_size"])) 

73 

74 # store these class definitions for use elsewhere 

75 # this is needed to guarantee that the classes in _this_ module 

76 # are called, and that some other overriding class is not used. 

77 

78 self.aw_class_window = Simple_Stat_Window 

79 self.aw_class_stat = Simple_stat 

80 self.aw_class_table_mw = Simple_table_mw 

81 self.aw_class_label = Simple_label 

82 

83 # layout is handled by superclass! 

84 # retrieve the contents of the stats. popup and tips elements 

85 # for future use do this here so that subclasses don't have to bother 

86 

87 self.stats = [[None]*self.ncols for _ in range(self.nrows)] 

88 self.popups = [[None]*self.ncols for _ in range(self.nrows)] 

89 self.tips = [[None]*self.ncols for _ in range(self.nrows)] 

90 

91 for stat in self.game_params.stats: 

92 self.stats[self.game_params.stats[stat].rowcol[0]][self.game_params.stats[stat].rowcol[1]] \ 

93 = self.game_params.stats[stat].stat_name 

94 self.popups[self.game_params.stats[stat].rowcol[0]][self.game_params.stats[stat].rowcol[1]] \ 

95 = self.game_params.stats[stat].popup 

96 self.tips[self.game_params.stats[stat].rowcol[0]][self.game_params.stats[stat].rowcol[1]] \ 

97 = self.game_params.stats[stat].tip 

98 

99 def create_contents(self, container, i): 

100 # this is a call to whatever is in self.aw_class_window but it isn't obvious 

101 container.create_contents(i) 

102 

103 def update_contents(self, container, i): 

104 # this is a call to whatever is in self.aw_class_window but it isn't obvious 

105 container.update_contents(i) 

106 

107 def create_common(self, x, y): 

108 # invokes the simple_table_mw class (or similar) 

109 self.table_mw = self.aw_class_table_mw(self.hud, aw=self) 

110 return self.table_mw 

111 

112 def move_windows(self): 

113 super(Simple_HUD, self).move_windows() 

114 # 

115 # tell our mw that an update is needed (normally on table move) 

116 # custom code here, because we don't use the ['common'] element 

117 # to control menu position 

118 self.table_mw.move_windows() 

119 

120 def save_layout(self, *args): 

121 """Save new layout back to the aux element in the config file.""" 

122 

123 new_locs = { 

124 self.adj[int(i)]: ((pos[0]), (pos[1])) 

125 for i, pos in list(self.positions.items()) 

126 if i != 'common' 

127 } 

128 self.config.save_layout_set(self.hud.layout_set, self.hud.max, 

129 new_locs, self.hud.table.width, self.hud.table.height) 

130 

131 

132class Simple_Stat_Window(Aux_Base.Seat_Window): 

133 """Simple window class for stat windows.""" 

134 

135 def __init__(self, aw=None, seat=None): 

136 super(Simple_Stat_Window, self).__init__(aw, seat) 

137 self.popup_count = 0 

138 

139 def button_release_right(self, event): # show pop up 

140 widget = self.childAt(event.pos()) 

141 

142 if widget.stat_dict and self.popup_count == 0 and widget.aw_popup: 

143 # do not popup on empty blocks or if one is already active 

144 pu = Popup.popup_factory( 

145 seat=widget.aw_seat, 

146 stat_dict=widget.stat_dict, 

147 win=self, 

148 pop=self.aw.config.popup_windows[widget.aw_popup], 

149 hand_instance=self.aw.hud.hand_instance, 

150 config=self.aw.config) 

151 pu.setStyleSheet(f"QWidget{{background:{self.aw.bgcolor};color:{self.aw.fgcolor};}}QToolTip{{}}") 

152 

153 def create_contents(self, i): 

154 self.setStyleSheet(f"QWidget{{background:{self.aw.bgcolor};color:{self.aw.fgcolor};}}QToolTip{{}}") 

155 self.grid = QGridLayout() 

156 self.grid.setHorizontalSpacing(4) 

157 self.grid.setVerticalSpacing(1) 

158 self.grid.setContentsMargins(2, 2, 2, 2) 

159 self.setLayout(self.grid) 

160 self.stat_box = [[None]*self.aw.ncols for _ in range(self.aw.nrows)] 

161 

162 for r in range(self.aw.nrows): 

163 for c in range(self.aw.ncols): 

164 self.stat_box[r][c] = self.aw.aw_class_stat(self.aw.stats[r][c], 

165 seat=self.seat, 

166 popup=self.aw.popups[r][c], 

167 game_stat_config=self.aw.hud.supported_games_parameters["game_stat_set"].stats[(r, c)], 

168 aw=self.aw) 

169 self.grid.addWidget(self.stat_box[r][c].widget, r, c) 

170 self.stat_box[r][c].widget.setFont(self.aw.font) 

171 

172 def update_contents(self, i): 

173 if i == "common": 

174 return 

175 player_id = self.aw.get_id_from_seat(i) 

176 if player_id is None: 

177 return 

178 for r in range(self.aw.nrows): 

179 for c in range(self.aw.ncols): 

180 self.stat_box[r][c].update(player_id, self.aw.hud.stat_dict) 

181 

182 

183class Simple_stat(object): 

184 """A simple class for displaying a single stat.""" 

185 def __init__(self, stat, seat, popup, game_stat_config=None, aw=None): 

186 self.stat = stat 

187 self.lab = aw.aw_class_label("xxx") # xxx is used as initial value because longer labels don't shrink 

188 self.lab.setAlignment(Qt.AlignCenter) 

189 self.lab.aw_seat = aw.hud.layout.hh_seats[seat] 

190 self.lab.aw_popup = popup 

191 self.lab.stat_dict = None 

192 self.widget = self.lab 

193 self.stat_dict = None 

194 self.hud = aw.hud 

195 self.aux_params = aw.aux_params 

196 

197 def update(self, player_id, stat_dict): 

198 self.stat_dict = stat_dict # So the Simple_stat obj always has a fresh stat_dict 

199 self.lab.stat_dict = stat_dict 

200 self.number = Stats.do_stat(stat_dict, player_id, self.stat, self.hud.hand_instance) 

201 if self.number: 

202 self.lab.setText(str(self.number[1])) 

203 

204 def set_color(self, fg=None, bg=None): 

205 ss = f"QLabel{{font-family: {self.aux_params['font']};font-size: {self.aux_params['font_size']}pt;" 

206 if fg: 

207 ss += f"color: {fg};" 

208 if bg: 

209 ss += f"background: {bg};" 

210 #print(f"Setting style sheet: {ss}") 

211 self.lab.setStyleSheet(ss + "}") 

212 

213 

214class Simple_label(QLabel): 

215 pass 

216 

217 

218 

219class Simple_table_mw(Aux_Base.Seat_Window): 

220 """Create a default table hud menu label""" 

221# This is a recreation of the table main window from the default HUD 

222# in the old Hud.py. This has the menu options from that hud.  

223 

224# BTW: It might be better to do this with a different AW. 

225 

226 def __init__(self, hud, aw = None): 

227 super(Simple_table_mw, self).__init__(aw) 

228 self.hud = hud 

229 self.aw = aw 

230 self.menu_is_popped = False 

231 

232 # self.connect("configure_event", self.configure_event_cb, "auxmenu") base class will deal with this 

233 

234 try: 

235 self.menu_label = hud.hud_params['label'] 

236 except Exception: 

237 self.menu_label = "fpdb menu" 

238 

239 lab = QLabel(self.menu_label) 

240 logo = os.path.join(Configuration.GRAPHICS_PATH, 'tribal.jpg') 

241 pixmap = QPixmap(logo) 

242 pixmap = pixmap.scaled(45, 45) 

243 lab.setPixmap(pixmap) 

244 lab.setStyleSheet(f"background: {self.aw.bgcolor}; color: {self.aw.fgcolor};") 

245 

246 self.setLayout(QVBoxLayout()) 

247 self.layout().setContentsMargins(0, 0, 0, 0) 

248 self.layout().addWidget(lab) 

249 

250 self.move(self.hud.table.x + self.aw.xshift, self.hud.table.y + self.aw.yshift) 

251 

252 def button_press_right(self, event): 

253 """Handle button clicks in the FPDB main menu event box.""" 

254 

255 if not self.menu_is_popped: 

256 self.menu_is_popped = True 

257 Simple_table_popup_menu(self) 

258 

259 def move_windows(self, *args): 

260 # force menu to the offset position from table origin (do not use common setting) 

261 self.move(self.hud.table.x + self.aw.xshift, self.hud.table.y + self.aw.yshift) 

262 

263 

264class Simple_table_popup_menu(QWidget): 

265 

266 def __init__(self, parentwin): 

267 

268 super(Simple_table_popup_menu, self).__init__(None, Qt.Window | Qt.FramelessWindowHint) 

269 self.parentwin = parentwin 

270 self.move(self.parentwin.hud.table.x + self.parentwin.aw.xshift, 

271 self.parentwin.hud.table.y + self.parentwin.aw.yshift) 

272 self.setWindowTitle(self.parentwin.menu_label) 

273 

274# combobox statrange 

275 stat_range_combo_dict = { 

276 0: ('Since:' + " " + 'All Time', "A"), 

277 1: ('Since:' + " " + 'Session', "S"), 

278 2: ('Since:' + " " + 'n Days' + " - - >", "T"), 

279 } 

280# combobox seatsstyle 

281 seats_style_combo_dict = { 

282 0: ('Number of Seats:' + " " + 'Any Number', "A"), 

283 1: ('Number of Seats:' + " " + 'Custom', "C"), 

284 2: ('Number of Seats:' + " " + 'Exact', "E"), 

285 } 

286# combobox multiplier 

287 multiplier_combo_dict = { 

288 0: ('For This Blind Level Only', 1), 

289 1: (' 0.5 to 2 * Current Blinds', 2), 

290 2: (' 0.33 to 3 * Current Blinds', 3), 

291 3: (' 0.1 to 10 * Current Blinds', 10), 

292 4: ('All Levels', 10000), 

293 } 

294# ComboBox - set max seats 

295 cb_max_dict = {0: ('Force layout'+'...', None)} 

296 for pos, i in enumerate((sorted(self.parentwin.hud.layout_set.layout)), start=1): 

297 cb_max_dict[pos] = (('%d-max' % i), i) 

298 grid = QGridLayout() 

299 self.setLayout(grid) 

300 vbox1 = QVBoxLayout() 

301 vbox2 = QVBoxLayout() 

302 vbox3 = QVBoxLayout() 

303 

304 vbox1.addWidget(self.build_button('Restart This HUD', "kill")) 

305 vbox1.addWidget(self.build_button('Save HUD Layout', "save")) 

306 vbox1.addWidget(self.build_button('Stop this HUD', "blacklist")) 

307 vbox1.addWidget(self.build_button('Close', "close")) 

308 vbox1.addWidget(QLabel('')) 

309 vbox1.addWidget(self.build_combo_and_set_active('new_max_seats', cb_max_dict)) 

310 

311 vbox2.addWidget(QLabel('Show Player Stats for')) 

312 vbox2.addWidget(self.build_combo_and_set_active('h_agg_bb_mult', multiplier_combo_dict)) 

313 vbox2.addWidget(self.build_combo_and_set_active('h_seats_style', seats_style_combo_dict)) 

314 hbox = QHBoxLayout() 

315 hbox.addWidget(QLabel('Custom')) 

316 self.h_nums_low_spinner = self.build_spinner('h_seats_cust_nums_low', 1, 9) 

317 hbox.addWidget(self.h_nums_low_spinner) 

318 hbox.addWidget(QLabel('To')) 

319 self.h_nums_high_spinner = self.build_spinner('h_seats_cust_nums_high', 2, 10) 

320 hbox.addWidget(self.h_nums_high_spinner) 

321 vbox2.addLayout(hbox) 

322 hbox = QHBoxLayout() 

323 hbox.addWidget(self.build_combo_and_set_active('h_stat_range', stat_range_combo_dict)) 

324 self.h_hud_days_spinner = self.build_spinner('h_hud_days', 1, 9999) 

325 hbox.addWidget(self.h_hud_days_spinner) 

326 vbox2.addLayout(hbox) 

327 

328 vbox3.addWidget(QLabel('Show Opponent Stats for')) 

329 vbox3.addWidget(self.build_combo_and_set_active('agg_bb_mult', multiplier_combo_dict)) 

330 vbox3.addWidget(self.build_combo_and_set_active('seats_style', seats_style_combo_dict)) 

331 hbox = QHBoxLayout() 

332 hbox.addWidget(QLabel('Custom')) 

333 self.nums_low_spinner = self.build_spinner('seats_cust_nums_low', 1, 9) 

334 hbox.addWidget(self.nums_low_spinner) 

335 hbox.addWidget(QLabel('To')) 

336 self.nums_high_spinner = self.build_spinner('seats_cust_nums_high', 2, 10) 

337 hbox.addWidget(self.nums_high_spinner) 

338 vbox3.addLayout(hbox) 

339 hbox = QHBoxLayout() 

340 hbox.addWidget(self.build_combo_and_set_active('stat_range', stat_range_combo_dict)) 

341 self.hud_days_spinner = self.build_spinner('hud_days', 1, 9999) 

342 hbox.addWidget(self.hud_days_spinner) 

343 vbox3.addLayout(hbox) 

344 

345 self.set_spinners_active() 

346 

347 grid.addLayout(vbox1, 0, 0) 

348 grid.addLayout(vbox2, 0, 1) 

349 grid.addLayout(vbox3, 0, 2) 

350 

351 self.show() 

352 self.raise_() 

353 

354 def delete_event(self): 

355 self.parentwin.menu_is_popped = False 

356 self.destroy() 

357 

358 def callback(self, checkState, data=None): 

359 if data == "kill": 

360 self.parentwin.hud.parent.kill_hud("kill", self.parentwin.hud.table.key) 

361 if data == "blacklist": 

362 self.parentwin.hud.parent.blacklist_hud("kill", self.parentwin.hud.table.key) 

363 if data == "save": 

364 # This calls the save_layout method of the Hud object. The Hud object  

365 # then calls the save_layout method in each installed AW. 

366 self.parentwin.hud.save_layout() 

367 self.delete_event() 

368 

369 def build_button(self, labeltext, cbkeyword): 

370 button = QPushButton(labeltext) 

371 button.clicked.connect(partial(self.callback, data=cbkeyword)) 

372 return button 

373 

374 def build_spinner(self, field, low, high): 

375 spinBox = QSpinBox() 

376 spinBox.setRange(low, high) 

377 spinBox.setValue(self.parentwin.hud.hud_params[field]) 

378 spinBox.valueChanged.connect(partial(self.change_spin_field_value, field=field)) 

379 return spinBox 

380 

381 def build_combo_and_set_active(self, field, combo_dict): 

382 widget = QComboBox() 

383 for pos in combo_dict: 

384 widget.addItem(combo_dict[pos][0]) 

385 if combo_dict[pos][1] == self.parentwin.hud.hud_params[field]: 

386 widget.setCurrentIndex(pos) 

387 widget.currentIndexChanged[int].connect(partial(self.change_combo_field_value, 

388 field=field, combo_dict=combo_dict)) 

389 return widget 

390 

391 def change_combo_field_value(self, sel, field, combo_dict): 

392 self.parentwin.hud.hud_params[field] = combo_dict[sel][1] 

393 self.set_spinners_active() 

394 

395 def change_spin_field_value(self, value, field): 

396 self.parentwin.hud.hud_params[field] = value 

397 

398 def set_spinners_active(self): 

399 if self.parentwin.hud.hud_params['h_stat_range'] == "T": 

400 self.h_hud_days_spinner.setEnabled(True) 

401 else: 

402 self.h_hud_days_spinner.setEnabled(False) 

403 if self.parentwin.hud.hud_params['stat_range'] == "T": 

404 self.hud_days_spinner.setEnabled(True) 

405 else: 

406 self.hud_days_spinner.setEnabled(False) 

407 if self.parentwin.hud.hud_params['h_seats_style'] == "C": 

408 self.h_nums_low_spinner.setEnabled(True) 

409 self.h_nums_high_spinner.setEnabled(True) 

410 else: 

411 self.h_nums_low_spinner.setEnabled(False) 

412 self.h_nums_high_spinner.setEnabled(False) 

413 if self.parentwin.hud.hud_params['seats_style'] == "C": 

414 self.nums_low_spinner.setEnabled(True) 

415 self.nums_high_spinner.setEnabled(True) 

416 else: 

417 self.nums_low_spinner.setEnabled(False) 

418 self.nums_high_spinner.setEnabled(False)