2 # -*- coding: utf-8 -*-
5 Create and manage the hud overlays.
7 # Copyright 2008-2011 Ray E. Barker
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with this program; if not, write to the Free Software
22 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 ########################################################################
27 _
= L10n
.get_translation()
29 # Standard Library modules
34 # logging has been set up in fpdb.py or HUD_main.py, use their settings:
35 log
= logging
.getLogger("hud")
43 # win32 modules -- only imported on windows systems
49 # FreePokerTools modules
57 def importName(module_name
, name
):
58 """Import a named object 'name' from module 'module_name'."""
59 # Recipe 16.3 in the Python Cookbook, 2nd ed. Thanks!!!!
62 module
= __import__(module_name
, globals(), locals(), [name
])
65 return(getattr(module
, name
))
69 def __init__(self
, parent
, table
, max, poker_game
, config
, db_connection
):
70 # __init__ is (now) intended to be called from the stdin thread, so it
71 # cannot touch the gui
72 if parent
is None: # running from cli ..
78 self
.poker_game
= poker_game
80 self
.db_connection
= db_connection
83 self
.site
= table
.site
84 self
.mw_created
= False
85 self
.hud_params
= parent
.hud_params
86 self
.repositioningwindows
= False # used to keep reposition_windows from re-entering
88 self
.stat_windows
= {}
89 self
.popup_windows
= {}
92 # configure default font and colors from the configuration
93 (font
, font_size
) = config
.get_default_font(self
.table
.site
)
94 self
.colors
= config
.get_default_colors(self
.table
.site
)
95 self
.hud_ui
= config
.get_hud_ui_parameters()
96 self
.site_params
= config
.get_site_parameters(self
.table
.site
)
98 self
.backgroundcolor
= gtk
.gdk
.color_parse(self
.colors
['hudbgcolor'])
99 self
.foregroundcolor
= gtk
.gdk
.color_parse(self
.colors
['hudfgcolor'])
101 self
.font
= pango
.FontDescription("%s %s" % (font
, font_size
))
102 # do we need to add some sort of condition here for dealing with a request for a font that doesn't exist?
104 game_params
= config
.get_game_parameters(self
.poker_game
)
105 # if there are AUX windows configured, set them up (Ray knows how this works, if anyone needs info)
106 if not game_params
['aux'] == [""]:
107 for aux
in game_params
['aux']:
108 aux_params
= config
.get_aux_parameters(aux
)
109 my_import
= importName(aux_params
['module'], aux_params
['class'])
110 if my_import
== None:
112 self
.aux_windows
.append(my_import(self
, config
, aux_params
))
114 self
.creation_attrs
= None
116 # Set up a main window for this this instance of the HUD
119 win
.set_skip_taskbar_hint(True) # invisible to taskbar
120 win
.set_gravity(gtk
.gdk
.GRAVITY_STATIC
)
121 # give it a title that we can easily filter out in the window list when Table search code is looking
122 win
.set_title("%s FPDBHUD" % (self
.table
.name
))
123 win
.set_decorated(False) # kill titlebars
124 win
.set_opacity(self
.colors
["hudopacity"])
126 win
.set_focus_on_map(False)
127 win
.set_accept_focus(False)
129 eventbox
= gtk
.EventBox()
130 label
= gtk
.Label(self
.hud_ui
['label'])
135 # set it to the desired color of the HUD for this site
136 label
.modify_bg(gtk
.STATE_NORMAL
, self
.backgroundcolor
)
137 label
.modify_fg(gtk
.STATE_NORMAL
, self
.foregroundcolor
)
139 eventbox
.modify_bg(gtk
.STATE_NORMAL
, self
.backgroundcolor
)
140 eventbox
.modify_fg(gtk
.STATE_NORMAL
, self
.foregroundcolor
)
142 self
.main_window
= win
143 # move it to the table window's X/Y position (0,0 on the table window usually)
144 self
.main_window
.move(self
.table
.x
, self
.table
.y
)
146 # A popup menu for the main window
147 # This menu code has become extremely long - is there a better way to do this?
150 killitem
= gtk
.MenuItem(_('Kill This HUD'))
151 menu
.append(killitem
)
152 if self
.parent
is not None:
153 killitem
.connect("activate", self
.parent
.kill_hud
, self
.table_name
)
155 saveitem
= gtk
.MenuItem(_('Save HUD Layout'))
156 menu
.append(saveitem
)
157 saveitem
.connect("activate", self
.save_layout
)
159 repositem
= gtk
.MenuItem(_('Reposition StatWindows'))
160 menu
.append(repositem
)
161 repositem
.connect("activate", self
.reposition_windows
)
163 aggitem
= gtk
.MenuItem(_('Show Player Stats'))
165 self
.aggMenu
= gtk
.Menu()
166 aggitem
.set_submenu(self
.aggMenu
)
167 # set agg_bb_mult to 1 to stop aggregation
168 item
= gtk
.CheckMenuItem(_('For This Blind Level Only'))
169 self
.aggMenu
.append(item
)
170 item
.connect("activate", self
.set_aggregation
, ('P', 1))
171 setattr(self
, 'h_aggBBmultItem1', item
)
173 item
= gtk
.MenuItem(_('For Multiple Blind Levels:'))
174 self
.aggMenu
.append(item
)
176 item
= gtk
.CheckMenuItem(_(' 0.5 to 2.0 x Current Blinds'))
177 self
.aggMenu
.append(item
)
178 item
.connect("activate", self
.set_aggregation
, ('P',2))
179 setattr(self
, 'h_aggBBmultItem2', item
)
181 item
= gtk
.CheckMenuItem(_(' 0.33 to 3.0 x Current Blinds'))
182 self
.aggMenu
.append(item
)
183 item
.connect("activate", self
.set_aggregation
, ('P',3))
184 setattr(self
, 'h_aggBBmultItem3', item
)
186 item
= gtk
.CheckMenuItem(_(' 0.1 to 10 x Current Blinds'))
187 self
.aggMenu
.append(item
)
188 item
.connect("activate", self
.set_aggregation
, ('P',10))
189 setattr(self
, 'h_aggBBmultItem10', item
)
191 item
= gtk
.CheckMenuItem(_(' All Levels'))
192 self
.aggMenu
.append(item
)
193 item
.connect("activate", self
.set_aggregation
, ('P',10000))
194 setattr(self
, 'h_aggBBmultItem10000', item
)
196 item
= gtk
.MenuItem(_('For #Seats:'))
197 self
.aggMenu
.append(item
)
199 item
= gtk
.CheckMenuItem(_(' Any Number'))
200 self
.aggMenu
.append(item
)
201 item
.connect("activate", self
.set_seats_style
, ('P','A'))
202 setattr(self
, 'h_seatsStyleOptionA', item
)
204 item
= gtk
.CheckMenuItem(_(' Custom'))
205 self
.aggMenu
.append(item
)
206 item
.connect("activate", self
.set_seats_style
, ('P','C'))
207 setattr(self
, 'h_seatsStyleOptionC', item
)
209 item
= gtk
.CheckMenuItem(_(' Exact'))
210 self
.aggMenu
.append(item
)
211 item
.connect("activate", self
.set_seats_style
, ('P','E'))
212 setattr(self
, 'h_seatsStyleOptionE', item
)
214 item
= gtk
.MenuItem(_('Since:'))
215 self
.aggMenu
.append(item
)
217 item
= gtk
.CheckMenuItem(_(' All Time'))
218 self
.aggMenu
.append(item
)
219 item
.connect("activate", self
.set_hud_style
, ('P','A'))
220 setattr(self
, 'h_hudStyleOptionA', item
)
222 item
= gtk
.CheckMenuItem(_(' Session'))
223 self
.aggMenu
.append(item
)
224 item
.connect("activate", self
.set_hud_style
, ('P','S'))
225 setattr(self
, 'h_hudStyleOptionS', item
)
227 item
= gtk
.CheckMenuItem(_(' %s Days') % (self
.hud_params
['h_hud_days']))
228 self
.aggMenu
.append(item
)
229 item
.connect("activate", self
.set_hud_style
, ('P','T'))
230 setattr(self
, 'h_hudStyleOptionT', item
)
232 aggitem
= gtk
.MenuItem(_('Show Opponent Stats'))
234 self
.aggMenu
= gtk
.Menu()
235 aggitem
.set_submenu(self
.aggMenu
)
236 # set agg_bb_mult to 1 to stop aggregation
237 item
= gtk
.CheckMenuItem(_('For This Blind Level Only'))
238 self
.aggMenu
.append(item
)
239 item
.connect("activate", self
.set_aggregation
, ('O',1))
240 setattr(self
, 'aggBBmultItem1', item
)
242 item
= gtk
.MenuItem(_('For Multiple Blind Levels:'))
243 self
.aggMenu
.append(item
)
245 item
= gtk
.CheckMenuItem(_(' 0.5 to 2.0 x Current Blinds'))
246 self
.aggMenu
.append(item
)
247 item
.connect("activate", self
.set_aggregation
, ('O',2))
248 setattr(self
, 'aggBBmultItem2', item
)
250 item
= gtk
.CheckMenuItem(_(' 0.33 to 3.0 x Current Blinds'))
251 self
.aggMenu
.append(item
)
252 item
.connect("activate", self
.set_aggregation
, ('O',3))
253 setattr(self
, 'aggBBmultItem3', item
)
255 item
= gtk
.CheckMenuItem(_(' 0.1 to 10 x Current Blinds'))
256 self
.aggMenu
.append(item
)
257 item
.connect("activate", self
.set_aggregation
, ('O',10))
258 setattr(self
, 'aggBBmultItem10', item
)
260 item
= gtk
.CheckMenuItem(_(' All Levels'))
261 self
.aggMenu
.append(item
)
262 item
.connect("activate", self
.set_aggregation
, ('O',10000))
263 setattr(self
, 'aggBBmultItem10000', item
)
265 item
= gtk
.MenuItem(_('For #Seats:'))
266 self
.aggMenu
.append(item
)
268 item
= gtk
.CheckMenuItem(_(' Any Number'))
269 self
.aggMenu
.append(item
)
270 item
.connect("activate", self
.set_seats_style
, ('O','A'))
271 setattr(self
, 'seatsStyleOptionA', item
)
273 item
= gtk
.CheckMenuItem(_(' Custom'))
274 self
.aggMenu
.append(item
)
275 item
.connect("activate", self
.set_seats_style
, ('O','C'))
276 setattr(self
, 'seatsStyleOptionC', item
)
278 item
= gtk
.CheckMenuItem(_(' Exact'))
279 self
.aggMenu
.append(item
)
280 item
.connect("activate", self
.set_seats_style
, ('O','E'))
281 setattr(self
, 'seatsStyleOptionE', item
)
283 item
= gtk
.MenuItem(_('Since:'))
284 self
.aggMenu
.append(item
)
286 item
= gtk
.CheckMenuItem(_(' All Time'))
287 self
.aggMenu
.append(item
)
288 item
.connect("activate", self
.set_hud_style
, ('O','A'))
289 setattr(self
, 'hudStyleOptionA', item
)
291 item
= gtk
.CheckMenuItem(_(' Session'))
292 self
.aggMenu
.append(item
)
293 item
.connect("activate", self
.set_hud_style
, ('O','S'))
294 setattr(self
, 'hudStyleOptionS', item
)
296 item
= gtk
.CheckMenuItem(_(' %s Days') % (self
.hud_params
['hud_days']))
297 self
.aggMenu
.append(item
)
298 item
.connect("activate", self
.set_hud_style
, ('O','T'))
299 setattr(self
, 'hudStyleOptionT', item
)
301 # set active on current options:
302 if self
.hud_params
['h_agg_bb_mult'] == 1:
303 getattr(self
, 'h_aggBBmultItem1').set_active(True)
304 elif self
.hud_params
['h_agg_bb_mult'] == 2:
305 getattr(self
, 'h_aggBBmultItem2').set_active(True)
306 elif self
.hud_params
['h_agg_bb_mult'] == 3:
307 getattr(self
, 'h_aggBBmultItem3').set_active(True)
308 elif self
.hud_params
['h_agg_bb_mult'] == 10:
309 getattr(self
, 'h_aggBBmultItem10').set_active(True)
310 elif self
.hud_params
['h_agg_bb_mult'] > 9000:
311 getattr(self
, 'h_aggBBmultItem10000').set_active(True)
313 if self
.hud_params
['agg_bb_mult'] == 1:
314 getattr(self
, 'aggBBmultItem1').set_active(True)
315 elif self
.hud_params
['agg_bb_mult'] == 2:
316 getattr(self
, 'aggBBmultItem2').set_active(True)
317 elif self
.hud_params
['agg_bb_mult'] == 3:
318 getattr(self
, 'aggBBmultItem3').set_active(True)
319 elif self
.hud_params
['agg_bb_mult'] == 10:
320 getattr(self
, 'aggBBmultItem10').set_active(True)
321 elif self
.hud_params
['agg_bb_mult'] > 9000:
322 getattr(self
, 'aggBBmultItem10000').set_active(True)
324 if self
.hud_params
['h_seats_style'] == 'A':
325 getattr(self
, 'h_seatsStyleOptionA').set_active(True)
326 elif self
.hud_params
['h_seats_style'] == 'C':
327 getattr(self
, 'h_seatsStyleOptionC').set_active(True)
328 elif self
.hud_params
['h_seats_style'] == 'E':
329 getattr(self
, 'h_seatsStyleOptionE').set_active(True)
331 if self
.hud_params
['seats_style'] == 'A':
332 getattr(self
, 'seatsStyleOptionA').set_active(True)
333 elif self
.hud_params
['seats_style'] == 'C':
334 getattr(self
, 'seatsStyleOptionC').set_active(True)
335 elif self
.hud_params
['seats_style'] == 'E':
336 getattr(self
, 'seatsStyleOptionE').set_active(True)
338 if self
.hud_params
['h_hud_style'] == 'A':
339 getattr(self
, 'h_hudStyleOptionA').set_active(True)
340 elif self
.hud_params
['h_hud_style'] == 'S':
341 getattr(self
, 'h_hudStyleOptionS').set_active(True)
342 elif self
.hud_params
['h_hud_style'] == 'T':
343 getattr(self
, 'h_hudStyleOptionT').set_active(True)
345 if self
.hud_params
['hud_style'] == 'A':
346 getattr(self
, 'hudStyleOptionA').set_active(True)
347 elif self
.hud_params
['hud_style'] == 'S':
348 getattr(self
, 'hudStyleOptionS').set_active(True)
349 elif self
.hud_params
['hud_style'] == 'T':
350 getattr(self
, 'hudStyleOptionT').set_active(True)
352 eventbox
.connect_object("button-press-event", self
.on_button_press
, menu
)
354 debugitem
= gtk
.MenuItem(_('Debug StatWindows'))
355 menu
.append(debugitem
)
356 debugitem
.connect("activate", self
.debug_stat_windows
)
358 item5
= gtk
.MenuItem(_('Set max seats'))
360 maxSeatsMenu
= gtk
.Menu()
361 item5
.set_submenu(maxSeatsMenu
)
362 for i
in range(2, 11, 1):
363 item
= gtk
.MenuItem('%d-max' % i
)
365 maxSeatsMenu
.append(item
)
366 item
.connect("activate", self
.change_max_seats
)
367 setattr(self
, 'maxSeatsMenuItem%d' % (i
- 1), item
)
369 eventbox
.connect_object("button-press-event", self
.on_button_press
, menu
)
371 self
.mw_created
= True
374 self
.main_window
.show_all()
375 # self.topify_window(self.main_window)
377 def change_max_seats(self
, widget
):
378 if self
.max != widget
.ms
:
379 #print 'change_max_seats', widget.ms
383 self
.create(*self
.creation_attrs
)
384 self
.update(self
.hand
, self
.config
)
386 log
.error("Exception:",str(e
))
389 def set_aggregation(self
, widget
, val
):
390 (player_opp
, num
) = val
391 if player_opp
== 'P':
392 # set these true all the time, set the multiplier to 1 to turn agg off:
393 self
.hud_params
['h_aggregate_ring'] = True
394 self
.hud_params
['h_aggregate_tour'] = True
396 if self
.hud_params
['h_agg_bb_mult'] != num \
397 and getattr(self
, 'h_aggBBmultItem'+str(num
)).get_active():
398 log
.debug('set_player_aggregation %d', num
)
399 self
.hud_params
['h_agg_bb_mult'] = num
400 for mult
in ('1', '2', '3', '10', '10000'):
402 getattr(self
, 'h_aggBBmultItem'+mult
).set_active(False)
404 self
.hud_params
['aggregate_ring'] = True
405 self
.hud_params
['aggregate_tour'] = True
407 if self
.hud_params
['agg_bb_mult'] != num \
408 and getattr(self
, 'aggBBmultItem'+str(num
)).get_active():
409 log
.debug('set_opponent_aggregation %d', num
)
410 self
.hud_params
['agg_bb_mult'] = num
411 for mult
in ('1', '2', '3', '10', '10000'):
413 getattr(self
, 'aggBBmultItem'+mult
).set_active(False)
415 def set_seats_style(self
, widget
, val
):
416 (player_opp
, style
) = val
417 if player_opp
== 'P':
418 param
= 'h_seats_style'
421 param
= 'seats_style'
424 if style
== 'A' and getattr(self
, prefix
+'seatsStyleOptionA').get_active():
425 self
.hud_params
[param
] = 'A'
426 getattr(self
, prefix
+'seatsStyleOptionC').set_active(False)
427 getattr(self
, prefix
+'seatsStyleOptionE').set_active(False)
428 elif style
== 'C' and getattr(self
, prefix
+'seatsStyleOptionC').get_active():
429 self
.hud_params
[param
] = 'C'
430 getattr(self
, prefix
+'seatsStyleOptionA').set_active(False)
431 getattr(self
, prefix
+'seatsStyleOptionE').set_active(False)
432 elif style
== 'E' and getattr(self
, prefix
+'seatsStyleOptionE').get_active():
433 self
.hud_params
[param
] = 'E'
434 getattr(self
, prefix
+'seatsStyleOptionA').set_active(False)
435 getattr(self
, prefix
+'seatsStyleOptionC').set_active(False)
436 log
.debug("setting self.hud_params[%s] = %s" % (param
, style
))
438 def set_hud_style(self
, widget
, val
):
439 (player_opp
, style
) = val
440 if player_opp
== 'P':
441 param
= 'h_hud_style'
447 if style
== 'A' and getattr(self
, prefix
+'hudStyleOptionA').get_active():
448 self
.hud_params
[param
] = 'A'
449 getattr(self
, prefix
+'hudStyleOptionS').set_active(False)
450 getattr(self
, prefix
+'hudStyleOptionT').set_active(False)
451 elif style
== 'S' and getattr(self
, prefix
+'hudStyleOptionS').get_active():
452 self
.hud_params
[param
] = 'S'
453 getattr(self
, prefix
+'hudStyleOptionA').set_active(False)
454 getattr(self
, prefix
+'hudStyleOptionT').set_active(False)
455 elif style
== 'T' and getattr(self
, prefix
+'hudStyleOptionT').get_active():
456 self
.hud_params
[param
] = 'T'
457 getattr(self
, prefix
+'hudStyleOptionA').set_active(False)
458 getattr(self
, prefix
+'hudStyleOptionS').set_active(False)
459 log
.debug("setting self.hud_params[%s] = %s" % (param
, style
))
461 def update_table_position(self
):
462 # get table's X/Y position on the desktop, and relocate all of our child windows to accomodate
463 # In Windows, we can verify the existence of a Window, with win32gui.IsWindow(). In Linux, there doesn't seem to be a
464 # way to verify the existence of a Window, without trying to access it, which if it doesn't exist anymore, results in a
465 # big giant X trap and crash.
466 # People tell me this is a bad idea, because theoretically, IsWindow() could return true now, but not be true when we actually
467 # use it, but accessing a dead window doesn't result in a complete windowing system shutdown in Windows, whereas it does
470 if not win32gui
.IsWindow(self
.table
.number
):
471 self
.parent
.kill_hud(self
, self
.table
.name
)
472 self
.parent
.kill_hud(self
, self
.table
.name
.split(" ")[0])
473 #table.name is only a valid handle for ring games ! we are not killing tourney tables here.
475 # anyone know how to do this in unix, or better yet, trap the X11 error that is triggered when executing the get_origin() for a closed window?
476 if self
.table
.gdkhandle
is not None:
477 (oldx
, oldy
) = self
.table
.gdkhandle
.get_origin() # In Windows, this call returns (0,0) if it's an invalid window. In X, the X server is immediately killed.
478 #(x, y, width, height) = self.table.get_geometry()
479 #print "self.table.get_geometry=",x,y,width,height
480 if self
.table
.oldx
!= oldx
or self
.table
.oldy
!= oldy
: # If the current position does not equal the stored position, save the new position, and then move all the sub windows.
481 self
.table
.oldx
= oldx
482 self
.table
.oldy
= oldy
483 self
.main_window
.move(oldx
+ self
.site_params
['xshift'], oldy
+ self
.site_params
['yshift'])
484 adj
= self
.adj_seats(self
.hand
, self
.config
)
485 loc
= self
.config
.get_locations(self
.table
.site
, self
.max)
486 # TODO: is stat_windows getting converted somewhere from a list to a dict, for no good reason?
487 for i
, w
in enumerate(self
.stat_windows
.itervalues()):
488 (oldx
, oldy
) = loc
[adj
[i
+1]]
489 w
.relocate(oldx
, oldy
)
491 # While we're at it, fix the positions of mucked cards too
492 for aux
in self
.aux_windows
:
493 aux
.update_card_positions()
495 self
.reposition_windows()
496 # call reposition_windows, which apparently moves even hidden windows, where this function does not, even though they do the same thing, afaict
500 def up_update_table_position(self
):
501 # callback for table moved
503 # move the stat windows
504 (self
.table
.oldx
, self
.table
.oldy
) = self
.table
.gdkhandle
.get_origin()
505 adj
= self
.adj_seats(self
.hand
, self
.config
)
506 loc
= self
.config
.get_locations(self
.table
.site
, self
.max)
507 for i
, w
in enumerate(self
.stat_windows
.itervalues()):
508 (x
, y
) = loc
[adj
[i
+1]]
510 # move the main window - use the "old" position as it's already updated by the time we get here.
511 self
.main_window
.move(self
.table
.oldx
+ self
.site_params
['xshift'], self
.table
.oldy
+ self
.site_params
['yshift'])
513 for aux
in self
.aux_windows
:
514 aux
.update_card_positions()
517 def on_button_press(self
, widget
, event
):
518 if event
.button
== 1: # if primary button, start movement
519 self
.main_window
.begin_move_drag(event
.button
, int(event
.x_root
), int(event
.y_root
), event
.time
)
521 if event
.button
== 3: # if secondary button, popup our main popup window
522 widget
.popup(None, None, None, event
.button
, event
.time
)
526 def kill(self
, *args
):
527 # kill all stat_windows, popups and aux_windows in this HUD
528 # heap dead, burnt bodies, blood 'n guts, veins between my teeth
529 for s
in self
.stat_windows
.itervalues():
532 # throws "invalid window handle" in WinXP (sometimes?)
534 except: # TODO: what exception?
536 self
.stat_windows
= {}
537 # also kill any aux windows
538 for aux
in self
.aux_windows
:
540 self
.aux_windows
= []
542 def resize_windows(self
, *args
):
543 for w
in self
.stat_windows
.itervalues():
546 rel_x
= (w
.x
- self
.table
.x
) * self
.table
.width
/ self
.table
.oldwidth
547 rel_y
= (w
.y
- self
.table
.y
) * self
.table
.height
/ self
.table
.oldheight
548 w
.x
= self
.table
.x
+ rel_x
549 w
.y
= self
.table
.y
+ rel_y
550 w
.window
.move(w
.x
, w
.y
)
552 def reposition_windows(self
, *args
):
553 if self
.repositioningwindows
is True:
556 self
.repositioningwindows
= True
558 self
.update_table_position()
559 for w
in self
.stat_windows
.itervalues():
561 # print "in reposition, w =", w
563 # print "in reposition, w =", w, w.x, w.y
564 w
.window
.move(w
.x
, w
.y
)
565 self
.repositioningwindows
= False
568 def debug_stat_windows(self
, *args
):
569 # print self.table, "\n", self.main_window.window.get_transient_for()
570 for w
in self
.stat_windows
:
572 print self
.stat_windows
[w
].window
.window
.get_transient_for()
573 except AttributeError:
574 print "this window doesnt have get_transient_for"
576 def save_layout(self
, *args
):
577 new_layout
= [(0, 0)] * self
.max
578 for sw
in self
.stat_windows
:
579 loc
= self
.stat_windows
[sw
].window
.get_position()
580 new_loc
= (loc
[0] - self
.table
.x
, loc
[1] - self
.table
.y
)
581 new_layout
[self
.stat_windows
[sw
].adj
- 1] = new_loc
582 self
.config
.edit_layout(self
.table
.site
, self
.max, locations
=new_layout
)
583 # ask each aux to save its layout back to the config object
584 [aux
.save_layout() for aux
in self
.aux_windows
]
585 # save the config object back to the file
586 print _("Updating config file")
589 def adj_seats(self
, hand
, config
):
590 # determine how to adjust seating arrangements, if a "preferred seat" is set in the hud layout configuration
591 # Need range here, not xrange -> need the actual list
592 adj
= range(0, self
.max + 1) # default seat adjustments = no adjustment
593 # does the user have a fav_seat?
594 if self
.max not in config
.supported_sites
[self
.table
.site
].layout
:
595 sys
.stderr
.write(_("No layout found for %d-max games for site %s\n") % (self
.max, self
.table
.site
))
597 if self
.table
.site
!= None and int(config
.supported_sites
[self
.table
.site
].layout
[self
.max].fav_seat
) > 0:
599 fav_seat
= config
.supported_sites
[self
.table
.site
].layout
[self
.max].fav_seat
600 actual_seat
= self
.get_actual_seat(config
.supported_sites
[self
.table
.site
].screen_name
)
601 for i
in xrange(0, self
.max + 1):
605 adj
[j
] = fav_seat
+ i
606 if adj
[j
] > self
.max:
607 adj
[j
] = adj
[j
] - self
.max
608 except Exception, inst
:
609 sys
.stderr
.write(_("Exception in %s") % "Hud.adj_seats")
610 sys
.stderr
.write("Error:" + (" %s") % inst
) # __str__ allows args to printed directly
613 def get_actual_seat(self
, name
):
614 for key
in self
.stat_dict
:
615 if self
.stat_dict
[key
]['screen_name'] == name
:
616 return self
.stat_dict
[key
]['seat']
617 sys
.stderr
.write(_("Error finding actual seat.\n"))
619 def create(self
, hand
, config
, stat_dict
, cards
):
620 # update this hud, to the stats and players as of "hand"
621 # hand is the hand id of the most recent hand played at this table
623 # this method also manages the creating and destruction of stat
624 # windows via calls to the Stat_Window class
625 self
.creation_attrs
= hand
, config
, stat_dict
, cards
628 if not self
.mw_created
:
631 self
.stat_dict
= stat_dict
633 log
.info(_('Creating hud from hand ')+str(hand
))
634 adj
= self
.adj_seats(hand
, config
)
635 loc
= self
.config
.get_locations(self
.table
.site
, self
.max)
636 if loc
is None and self
.max != 10:
637 loc
= self
.config
.get_locations(self
.table
.site
, 10)
638 if loc
is None and self
.max != 9:
639 loc
= self
.config
.get_locations(self
.table
.site
, 9)
641 # create the stat windows
642 for i
in xrange(1, self
.max + 1):
644 if i
in self
.stat_windows
:
645 self
.stat_windows
[i
].relocate(x
, y
)
647 self
.stat_windows
[i
] = Stat_Window(game
= config
.supported_games
[self
.poker_game
],
657 self
.topify_window(self
.main_window
)
658 for i
in xrange(1, self
.max + 1):
659 self
.topify_window(self
.stat_windows
[i
].window
, self
.main_window
)
661 game
= config
.supported_games
[self
.poker_game
]
663 for i
in xrange(0, game
.rows
+ 1):
664 row_list
= [''] * game
.cols
665 self
.stats
.append(row_list
)
666 for stat
in game
.stats
:
667 self
.stats
[config
.supported_games
[self
.poker_game
].stats
[stat
].row
] \
668 [config
.supported_games
[self
.poker_game
].stats
[stat
].col
] = \
669 config
.supported_games
[self
.poker_game
].stats
[stat
].stat_name
671 # if os.name == "nt": # we call update_table_position() regularly in Windows to see if we're moving around. See comments on that function for why this isn't done in X.
672 # gobject.timeout_add(500, self.update_table_position)
674 def update(self
, hand
, config
):
675 self
.hand
= hand
# this is the last hand, so it is available later
677 if self
.update_table_position() == False: # we got killed by finding our table was gone
680 self
.label
.modify_fg(gtk
.STATE_NORMAL
, gtk
.gdk
.color_parse(self
.colors
['hudfgcolor']))
681 for s
in self
.stat_dict
:
683 statd
= self
.stat_dict
[s
]
685 log
.error(_("KeyError at the start of the for loop in update in hud_main. How this can possibly happen is totally beyond my comprehension. Your HUD may be about to get really weird. -Eric"))
686 log
.error(_("(btw, the key was %s and statd is %s") % (s
, statd
))
689 self
.stat_windows
[statd
['seat']].player_id
= statd
['player_id']
690 #self.stat_windows[self.stat_dict[s]['seat']].player_id = self.stat_dict[s]['player_id']
691 except KeyError: # omg, we have more seats than stat windows .. damn poker sites with incorrect max seating info .. let's force 10 here
693 self
.create(hand
, config
, self
.stat_dict
, self
.cards
)
694 self
.stat_windows
[statd
['seat']].player_id
= statd
['player_id']
696 for r
in xrange(0, config
.supported_games
[self
.poker_game
].rows
):
697 for c
in xrange(0, config
.supported_games
[self
.poker_game
].cols
):
698 this_stat
= config
.supported_games
[self
.poker_game
].stats
[self
.stats
[r
][c
]]
699 number
= Stats
.do_stat(self
.stat_dict
, player
= statd
['player_id'], stat
= self
.stats
[r
][c
])
700 statstring
= "%s%s%s" % (this_stat
.hudprefix
, str(number
[1]), this_stat
.hudsuffix
)
701 window
= self
.stat_windows
[statd
['seat']]
703 if this_stat
.hudcolor
!= "":
704 window
.label
[r
][c
].modify_fg(gtk
.STATE_NORMAL
, gtk
.gdk
.color_parse(this_stat
.hudcolor
))
706 window
.label
[r
][c
].modify_fg(gtk
.STATE_NORMAL
, gtk
.gdk
.color_parse(self
.colors
['hudfgcolor']))
708 if this_stat
.stat_loth
!= "":
709 if number
[0] < (float(this_stat
.stat_loth
)/100):
710 window
.label
[r
][c
].modify_fg(gtk
.STATE_NORMAL
, gtk
.gdk
.color_parse(this_stat
.stat_locolor
))
712 if this_stat
.stat_hith
!= "":
713 if number
[0] > (float(this_stat
.stat_hith
)/100):
714 window
.label
[r
][c
].modify_fg(gtk
.STATE_NORMAL
, gtk
.gdk
.color_parse(this_stat
.stat_hicolor
))
716 window
.label
[r
][c
].set_text(statstring
)
717 if statstring
!= "xxx": # is there a way to tell if this particular stat window is visible already, or no?
719 tip
= "%s\n%s\n%s, %s" % (statd
['screen_name'], number
[5], number
[3], number
[4])
720 Stats
.do_tip(window
.e_box
[r
][c
], tip
)
721 if unhidewindow
: #and not window.window.visible: # there is no "visible" attribute in gtk.Window, although the docs seem to indicate there should be
722 window
.window
.show_all()
725 def topify_window(self
, window
, parentwindow
=None):
726 window
.set_focus_on_map(False)
727 window
.set_accept_focus(False)
728 # print "topify_window", window, parentwindow
730 if not self
.table
.gdkhandle
:
731 self
.table
.gdkhandle
= gtk
.gdk
.window_foreign_new(int(self
.table
.number
)) # gtk handle to poker window
732 if parentwindow
is not None:
733 window
.window
.set_transient_for(parentwindow
.window
)
735 window
.window
.set_transient_for(self
.table
.gdkhandle
)
736 window
.set_destroy_with_parent(True)
740 def button_press_cb(self
, widget
, event
, *args
):
741 # This handles all callbacks from button presses on the event boxes in
742 # the stat windows. There is a bit of an ugly kludge to separate single-
744 self
.window
.show() #_all()
746 if event
.button
== 3: # right button event
747 newpopup
= Popup_window(self
.window
, self
)
748 #print "added popup", newpopup
749 # TODO: how should we go about making sure it doesn't open a dozen popups if you click?
750 self
.popups
.append(newpopup
)
753 if event
.button
== 2: # middle button event
757 if event
.button
== 1: # left button event
758 # close on double click for a stat window
759 # for those that don't have a mouse with middle button
760 if event
.type == gtk
.gdk
._2BUTTON
_PRESS
:
763 # TODO: make position saving save sizes as well?
764 if event
.state
& gtk
.gdk
.SHIFT_MASK
:
765 self
.window
.begin_resize_drag(gtk
.gdk
.WINDOW_EDGE_SOUTH_EAST
, event
.button
, int(event
.x_root
), int(event
.y_root
), event
.time
)
767 self
.window
.begin_move_drag(event
.button
, int(event
.x_root
), int(event
.y_root
), event
.time
)
771 def noop(self
, arga
=None, argb
=None): # i'm going to try to connect the focus-in and focus-out events here, to see if that fixes any of the focus problems.
774 def kill_popup(self
, popup
):
775 #print "remove popup", popup
776 self
.popups
.remove(popup
)
777 popup
.window
.destroy()
779 def kill_popups(self
):
780 map(lambda x
: x
.window
.destroy(), self
.popups
)
783 def relocate(self
, x
, y
):
784 self
.x
= x
+ self
.table
.oldx
785 self
.y
= y
+ self
.table
.oldy
786 self
.window
.move(self
.x
, self
.y
)
788 def __init__(self
, parent
, game
, table
, seat
, adj
, x
, y
, player_id
, font
):
789 self
.parent
= parent
# Hud object that this stat window belongs to
790 self
.game
= game
# Configuration object for the curren
791 self
.table
= table
# Table object where this is going
792 self
.seat
= seat
# seat number of his player
793 self
.adj
= adj
# the adjusted seat number for this player
794 self
.x
= x
+ table
.x
# table.x and y are the location of the table
795 self
.y
= y
+ table
.y
# x and y are the location relative to table.x & y
796 self
.player_id
= player_id
# looks like this isn't used ;)
797 self
.sb_click
= 0 # used to figure out button clicks
798 self
.popups
= [] # list of open popups for this stat window
799 self
.useframes
= parent
.config
.get_frames(parent
.site
)
801 self
.window
= gtk
.Window()
802 self
.window
.set_decorated(0)
803 self
.window
.set_property("skip-taskbar-hint", True)
804 self
.window
.set_gravity(gtk
.gdk
.GRAVITY_STATIC
)
806 self
.window
.set_title("%s" % seat
)
807 self
.window
.set_focus(None) # set gtk default focus widget for this window to None
808 self
.window
.set_focus_on_map(False)
809 self
.window
.set_accept_focus(False)
811 self
.window
.set_type_hint(gtk
.gdk
.WINDOW_TYPE_HINT_UTILITY
)
813 grid
= gtk
.Table(rows
= game
.rows
, columns
= game
.cols
, homogeneous
= False)
815 self
.window
.add(grid
)
816 self
.window
.modify_bg(gtk
.STATE_NORMAL
, parent
.backgroundcolor
)
821 usegtkframes
= self
.useframes
824 for r
in xrange(game
.rows
):
826 self
.frame
.append([])
829 for c
in xrange(game
.cols
):
831 self
.frame
[r
].append( gtk
.Frame() )
832 e_box
[r
].append( gtk
.EventBox() )
834 e_box
[r
][c
].modify_bg(gtk
.STATE_NORMAL
, parent
.backgroundcolor
)
835 e_box
[r
][c
].modify_fg(gtk
.STATE_NORMAL
, parent
.foregroundcolor
)
837 Stats
.do_tip(e_box
[r
][c
], 'stuff')
839 grid
.attach(self
.frame
[r
][c
], c
, c
+1, r
, r
+1, xpadding
= game
.xpad
, ypadding
= game
.ypad
)
840 self
.frame
[r
][c
].add(e_box
[r
][c
])
842 grid
.attach(e_box
[r
][c
], c
, c
+1, r
, r
+1, xpadding
= game
.xpad
, ypadding
= game
.ypad
)
843 label
[r
].append( gtk
.Label('xxx') )
846 self
.frame
[r
][c
].modify_bg(gtk
.STATE_NORMAL
, parent
.backgroundcolor
)
847 label
[r
][c
].modify_bg(gtk
.STATE_NORMAL
, parent
.backgroundcolor
)
848 label
[r
][c
].modify_fg(gtk
.STATE_NORMAL
, parent
.foregroundcolor
)
850 e_box
[r
][c
].add(self
.label
[r
][c
])
851 e_box
[r
][c
].connect("button_press_event", self
.button_press_cb
)
852 e_box
[r
][c
].connect("focus-in-event", self
.noop
)
853 e_box
[r
][c
].connect("focus", self
.noop
)
854 e_box
[r
][c
].connect("focus-out-event", self
.noop
)
855 label
[r
][c
].modify_font(font
)
857 self
.window
.set_opacity(parent
.colors
['hudopacity'])
858 self
.window
.connect("focus", self
.noop
)
859 self
.window
.connect("focus-in-event", self
.noop
)
860 self
.window
.connect("focus-out-event", self
.noop
)
861 self
.window
.connect("button_press_event", self
.button_press_cb
)
862 self
.window
.set_focus_on_map(False)
863 self
.window
.set_accept_focus(False)
866 self
.window
.move(self
.x
, self
.y
)
868 self
.window
.realize() # window must be realized before it has a gdkwindow so we can attach it to the table window..
869 # self.topify_window(self.window)
872 def destroy(*args
): # call back for terminating the main eventloop
876 def __init__(self
, parent
, stat_window
):
878 self
.stat_window
= stat_window
881 # create the popup window
882 self
.window
= gtk
.Window()
883 self
.window
.set_decorated(0)
884 self
.window
.set_gravity(gtk
.gdk
.GRAVITY_STATIC
)
885 self
.window
.set_title("popup")
886 self
.window
.set_property("skip-taskbar-hint", True)
887 self
.window
.set_focus_on_map(False)
888 self
.window
.set_accept_focus(False)
889 self
.window
.set_transient_for(parent
.get_toplevel())
891 self
.window
.set_position(gtk
.WIN_POS_CENTER_ON_PARENT
)
893 self
.ebox
= gtk
.EventBox()
894 self
.ebox
.connect("button_press_event", self
.button_press_cb
)
895 self
.lab
= gtk
.Label("stuff\nstuff\nstuff")
897 # need an event box so we can respond to clicks
898 self
.window
.add(self
.ebox
)
899 self
.ebox
.add(self
.lab
)
901 self
.ebox
.modify_bg(gtk
.STATE_NORMAL
, stat_window
.parent
.backgroundcolor
)
902 self
.ebox
.modify_fg(gtk
.STATE_NORMAL
, stat_window
.parent
.foregroundcolor
)
903 self
.window
.modify_bg(gtk
.STATE_NORMAL
, stat_window
.parent
.backgroundcolor
)
904 self
.window
.modify_fg(gtk
.STATE_NORMAL
, stat_window
.parent
.foregroundcolor
)
905 self
.lab
.modify_bg(gtk
.STATE_NORMAL
, stat_window
.parent
.backgroundcolor
)
906 self
.lab
.modify_fg(gtk
.STATE_NORMAL
, stat_window
.parent
.foregroundcolor
)
908 # figure out the row, col address of the click that activated the popup
911 for r
in xrange(0, stat_window
.game
.rows
):
912 for c
in xrange(0, stat_window
.game
.cols
):
913 if stat_window
.e_box
[r
][c
] == parent
:
918 # figure out what popup format we're using
919 popup_format
= "default"
920 for stat
in stat_window
.game
.stats
:
921 if stat_window
.game
.stats
[stat
].row
== row
and stat_window
.game
.stats
[stat
].col
== col
:
922 popup_format
= stat_window
.game
.stats
[stat
].popup
925 # get the list of stats to be presented from the config
927 for w
in stat_window
.parent
.config
.popup_windows
:
928 if w
== popup_format
:
929 stat_list
= stat_window
.parent
.config
.popup_windows
[w
].pu_stats
932 # get a database connection
933 # db_connection = Database.Database(stat_window.parent.config, stat_window.parent.db_name, 'temp')
935 # calculate the stat_dict and then create the text for the pu
936 # stat_dict = db_connection.get_stats_from_hand(stat_window.parent.hand, stat_window.player_id)
937 # stat_dict = self.db_connection.get_stats_from_hand(stat_window.parent.hand)
938 # db_connection.close_connection()
939 stat_dict
= stat_window
.parent
.stat_dict
943 number
= Stats
.do_stat(stat_dict
, player
= int(stat_window
.player_id
), stat
= s
)
944 mo_text
+= number
[5] + " " + number
[4] + "\n"
945 pu_text
+= number
[3] + "\n"
948 self
.lab
.set_text(pu_text
)
949 Stats
.do_tip(self
.lab
, mo_text
)
950 self
.window
.show_all()
952 self
.window
.set_transient_for(stat_window
.window
)
954 def button_press_cb(self
, widget
, event
, *args
):
955 # This handles all callbacks from button presses on the event boxes in
956 # the popup windows. There is a bit of an ugly kludge to separate single-
957 # and double-clicks. This is the same code as in the Stat_window class
958 if event
.button
== 1: # left button event
961 if event
.button
== 2: # middle button event
964 if event
.button
== 3: # right button event
965 self
.stat_window
.kill_popup(self
)
967 # self.window.destroy()
970 def toggle_decorated(self
, widget
):
971 top
= widget
.get_toplevel()
972 (x
, y
) = top
.get_position()
974 if top
.get_decorated():
981 def topify_window(self
, window
):
982 window
.set_focus_on_map(False)
983 window
.set_accept_focus(False)
985 if not self
.table
.gdkhandle
:
986 self
.table
.gdkhandle
= gtk
.gdk
.window_foreign_new(int(self
.table
.number
)) # gtk handle to poker window
987 # window.window.reparent(self.table.gdkhandle, 0, 0)
988 window
.window
.set_transient_for(self
.table
.gdkhandle
)