Using the Aux Window Feature

Introduction

The Aux_Window feature (AW hereinafter) is designed to provide a plug-in architecture for extending the fpdb gui. AWs are written in python and use the gtk widget set, just like fpdb—so some programming skill is required to product a new AW. The AW interface uses the python object oriented (OO) programming model, so some familiarity with python OO programming is needed. Links to python and gtk information are provided at the bottom of this page.

An AW is associated with a table. I have produced two useful AWs, FlopMucked and StudMucked, besides the demo AWs shown in this tutorial. The source for those AWs is in the Mucked.py module and this wiki page tells how to set then up. AWs have full access to all information in fpdb, and can execute long running database queries or calculations in a thread that does not block access to the gui.

AWs do not have to be compiled or distributed with fpdb. If you write an AW you can just drop it into the pyfpdb folder in your fpdb installation, reference it in the config file and start using it. We (the fpdb team) would be happy if you feed your new AW back to us and we will package and distribute useful, interesting, or fun AWs as long as they are not dangerous or harmful.

fpdb knows to import and use an AW when it is specified in the HUD_config.xml file. You can also add custom attributes in the config file that will be passed to the AW.

Interface Overview

An fpdb communicates with an AW through 4 methods (python functions). Most AWs will have to provide all 4 methods, though the Hello demo shown below implements only 1 method. An AW must also declare its class.

Class Definition

The class definition is required to name the class (the AW name) and to reference the Aux_Window class. This is so that the fpdb interface will recognize the code that follows as an AW and will know its name. A class definition for an AW named "Hello" looks like this:

class Hello(Aux_Window):

init() Method

Python programmers recognize the init(self) method as the standard way to initialize a new object, in this case an AW. Your init must have exactly 4 parameters, as shown in the code below. Those parameters are:
self a reference to this AW object
hud a reference to the HUD object that owns this AW
config an fpdb configuration object
params a python dictionary containing the attributes specified in the config for this AW

A minimal init(self) looks like this:

def __init__(self, hud, config, params):
self.hud        = hud
self.config     = config
self.params     = params

This example shows the hud, config, and params being saved as attributes of this AW (as self.hud, for example). This allows them to be used in other methods. This is required for all but the most trivial AWs.

You cannot interact with the gui in the init, the results will be unpredictable and are likely to cause a crash on some systems.

create() Method

The create() method is a companion of the init in that the create() is used to initialize the gui for the AW. You should create all the gtk widgets (windows, buttons, labels, etc.) in the create() method. Create() is called after init but before the other interface methods, so the data from the update_dat() method is not yet available to be displayed. Therefore, the create() method will usually just create the gtk widgets, but not populate them with the AW information. A create() method will always start with a def like this:

def create(self):

That statement will be followed by the python code needed to define the AW's gui.

update_data() Method

The update_data() method is where the number crunching happens in the AW. To that end, fpdb will pass the update_data() method the id of the last hand played and a database connection object. Update_data() is called after create() when the AW is initialized and then after each hand played on the table to which the AW is attached. The function of the update_data() method is to query the database or do the number crunching required to develop the information to be shown in the AW and then stash it away for display by the update_gui() method. An update_gui will start with a def that looks like this:

def update_data(self, new_hand_id, db_connection):

Update_data() is executed in a thread that does not block the gui and should not interact with any gui elements.

update_gui() Method

The update_gui() method displays the information developed by the update_data method and displays it in the AW's gui. The update_gui() method is executed just after the update_data() method when the AW is initialized, and the after update_data() after every hand is completed. The update_gui() will have a def that looks like this:

def update_gui(self, new_hand_id):

AS with the create() method, update_gui() runs in the gui thread and any long-running calculations or queries will freeze the gui until complete. Therefore, you should avoid long running calculations in this method.

Accessing HUD Information

All HUD data is available to the AW. Access it via the AW hud attirbute. A few examples are:

hud.parent      # the top level main_window object
hud.table       # the table object for the table
hud.poker_game  # the game being played, e.g., "holdem" or "razz"
hud.max         # max no of seats at this table
hud.site        # poker site, e.g., "FullTiltPoker"

So if you wanted to print the max seats at the table:

print self.hud.max

There is important information that many AWs will need: the stat information and the shown player and board cards. These are collected from the db after every new hand and stored in the hud object. For example to print the stat_dict and cards:

print self.hud.stat_dict
print self.hud.cards

The stat_dict is a dictionary with the information required to calculate the usual HUD stats. You can run the Stats.py module to get a list of the stats and their identity in English, or nearly English. The dictionary key is the player id from the Players table. An abbreviated stat_dict looks like this:

{7L: {'f_cb_2': Decimal("105"), 'f_freq_3': Decimal("100"), ...},
 238L: {'f_cb_2': Decimal("0"), 'f_freq_3': Decimal("0"), 'ccr_opp_4': Decimal("0"), ...},
 ...
}

Cards are also available in a dictionary. In this case the key is the seat number, or 'common' for community cards. An example Cards attribute looks like this:

{1: 'xxxx', 2: 'ThJs', 3: 'xxxx', 4: 'xxxx', 5: 'xxxx', 6: 'xxxx', 7: 'TdQs', 9: 'JhQh', 'common': 'KsAh4c7c8h'}

Accessing Database Information

fpdb passes the update_gui() method a reference to a database object when can be used to run database queries defined in the Database module or to run queries your custom queries. For example, to access the action from the current hand using the get_action_from_hand query:

def update_data(self, new_hand_id, db_connection):
action = db_connection.get_action_from_hand(new_hand_id)
print "action =", action

Here is an example of running your own sql code that retrieves the ids of the players and their stacks from the last hand:

def update_data(self, new_hand_id, db_connection):
stacks = []
c = db_connection.cursor()
c.execute("SELECT playerid, startCash FROM HandsPlayers WHERE handid = %d;" % int(new_hand_id))
for (id, stack) in c.fetchall():
stacks.append((id, stack))
print "stacks =", stacks
c.close

One handy tip: Do not close the db_connection, the HUD will die loudly and horribly.

Configuring the AW and Accessing the AW Configuration

You configure your AW through the HUD_config.xml file, just like everything else in fpdb. The configuration information for AWs goes in the aux_windows section. Currently, my aux_windows section looks like this:

<aux_windows>
<aw card_ht="42" card_wd="30" class="Stud_mucked" cols="11" deck="Cards0-HMHUD.png" module="Mucked" name="stud_mucked" rows="8"> </aw>
<aw class="Hello" module="Hello" name="Hello"> </aw>
<aw class="Hello_plus" module="Hello" name="Hello_plus"> </aw>
</aux_windows>

The class, module and name attributes are required and must be accurate or the AW will not open.

The name attribute is used to identify the particular AW configuration. The names not be repeated. You can have multiple AWs with the same module and class, as long as each has a unique name. For example, if I wanted to another StudMucked AW using the X cards, I would add this line to my config:

<aw card_ht="42" card_wd="30" class="Stud_mucked" cols="11" deck="Cards0-X.png" module="Mucked" name="stud_mucked-X" rows="8"> </aw>

The module attribute is the name of the python module (i.e., source file) that contains the python code for the AW. The ".py" at the end of the module name is understood. Normally, the module will be in the pyfpdb/ folder of the fpdb distribution, but it can be anywhere in the pythonpath of your installation. Spelling, punctuation and capitalization all matter.

The class attribute tells fpdb which class in your module is to be associated with this AW.

In order to make an AW appear, it must be associated with a game. To associate the "Hello_plus" AW with holdem, for example:

<game cols="3" db="fpdb" game_name="holdem" rows="2" aux="Hello_plus">
<stat
...
stat_name="wmsd" tip="tip1"> </stat>
</game>

The name in the aux attribute must match the name attribute of the AW you are specifying.

Accessing HUD Configuration Information

AWs have full access to the configuration information in the HUD_config.xml file via the Configuration object passes to the init() method. For example, you might might want to retrieve the list of supported games from the config.

def __init__(self, hud, config, params):
self.hud        = hud
self.config     = config
self.params     = params
 
games = self.config.get_supported_games()
print "games =", games

Useful Links

Python documentation, the tutorial is good. I use the quick reference sometimes.
pygtk tutorial Pygtk home is here. The pygtk tutorial is good. The pygtk FAQ is outstanding.

web analytics

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License