# Copied from Joystick.py: #---------------------------------------------------------------------------- # Name: Joystick.py # Purpose: Demonstrate use of wx.Joystick # # Author: Jeff Grimmett (grimmtoo@softhome.net), adapted from original # .wdr-derived demo # # Created: 02-Jan-2004 # RCS-ID: $Id: Joystick.py 30229 2004-11-01 19:39:09Z RD $ # Copyright: # Licence: wxWindows license #---------------------------------------------------------------------------- import wx, math from label import * class AxisBar(wx.Gauge): # # This class allows us to use a wx.Gauge to display the axis value # with a fancy label overlayed onto the guage itself. Two values are # used to do things: first of all, since the gauge is limited to # positive numbers, the scale is fixed at 0 to 1000. We will receive # an adjusted value to use to render the gauge itself. The other value # is a raw value and actually reflects the value from the joystick itself, # which is then drawn over the gauge. # def __init__(self, parent): wx.Gauge.__init__(self, parent, -1, 1000, size=(-1, 20), style = wx.GA_HORIZONTAL | wx.GA_SMOOTH ) # This is the value we will display. self.rawvalue = 0 self.SetBackgroundColour('light blue') self.SetForegroundColour('orange') # Capture paint events for purpose of updating # the displayed value. self.Bind(wx.EVT_PAINT, self.onPaint) def Update(self, value, rawvalue): # Updates the gauge itself, sets the raw value for # the next EVT_PAINT self.SetValue(value) self.rawvalue = rawvalue wx.Gauge.Update(self) def onPaint(self, evt): # Must always create a PaintDC when capturing # an EVT_PAINT event self.ShowValue(wx.PaintDC(self), evt) def ShowValue(self, dc, evt): # This method handles actual painting of and drawing # on the gauge. # Clear out the gauge dc.Clear() # and then carry out business as usual wx.Gauge.OnPaint(self, evt) # This is the size available to us. w, h = dc.GetSize() # This is what we will overlay on the gauge. # It reflects the actual value received from the # wx.Joystick. txt = str(self.rawvalue) # Copy the default font, make it bold. fn = wx.Font( self.GetFont().GetPointSize(), self.GetFont().GetFamily(), self.GetFont().GetStyle(), wx.BOLD ) # Set the font for the DC ... dc.SetFont(fn) # ... and calculate how much space our value # will take up. fw, fh = dc.GetTextExtent(txt) # Calc the center of the gauge, and from that # derive the origin of our value. center = w / 2 tx = center - (fw/2) center = h / 2 ty = center - (fh/2) # I draw the value twice so as to give it a pseudo-shadow. # This is (mostly) because I'm too lazy to figure out how # to blit my text onto the gauge using one of the logical # functions. The pseudo-shadow gives the text contrast # regardless of whether the bar is under it or not. dc.SetTextForeground(wx.BLACK) dc.DrawText(txt, tx, ty) dc.SetTextForeground('white') dc.DrawText(txt, tx-1, ty-1) #---------------------------------------------------------------------------- class Axis(wx.Panel): # # This class is a container for the min, max, and current # values of the joystick axis in question. It contains # also special features to render a 'dummy' if the axis # in question is not available. # def __init__(self, parent, token, stick): self.stick = stick # # token represents the type of axis we're displaying. # self.token = token # # Create a call to the 'Has*()' method for the stick. # X and Y are always there, so we tie the Has* method # to a hardwired True value. # if token not in ['X', 'Y']: self.HasFunc = eval('stick.Has%s' % token) else: self.HasFunc = self.alwaysTrue # Now init the panel. wx.Panel.__init__(self, parent, -1) sizer = wx.BoxSizer(wx.HORIZONTAL) if self.HasFunc(): # # Tie our calibration functions to the appropriate # stick method. If we don't have the axis in question, # we won't need them. # self.GetMin = eval('stick.Get%sMin' % token) self.GetMax = eval('stick.Get%sMax' % token) # Create our displays and set them up. self.Min = wx.StaticText(self, -1, str(self.GetMin()), style=wx.ALIGN_RIGHT) self.Max = wx.StaticText(self, -1, str(self.GetMax()), style=wx.ALIGN_LEFT) self.bar = AxisBar(self) sizer.Add(self.Min, 0, wx.ALL | wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL, 1) sizer.Add(self.bar, 1, wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL, 1) sizer.Add(self.Max, 0, wx.ALL | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, 1) else: # We go here if the axis in question is not available. self.control = wx.StaticText(self, -1, ' *** Not Present ***') sizer.Add(self.control, 1, wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL, 1) #---------------------------------------------------------------------------- self.SetSizer(sizer) sizer.Fit(self) wx.CallAfter(self.Update) def Calibrate(self): if not self.HasFunc(): return self.Min.SetLabel(str(self.GetMin())) self.Max.SetLabel(str(self.GetMax())) def Update(self): # Don't bother if the axis doesn't exist. if not self.HasFunc(): return min = int(self.Min.GetLabel()) max = int(self.Max.GetLabel()) # # Not all values are available from a wx.JoystickEvent, so I've elected # to not use it at all. Therefore, we are getting our values direct from # the stick. These values also seem to be more stable and reliable than # those received from the event itself, so maybe it's a good idea to # use the stick directly for your program. # # Here we either select the appropriate member of stick.GetPosition() or # apply the appropriate Get*Position method call. # if self.token == 'X': val = self.stick.GetPosition().x elif self.token == 'Y': val = self.stick.GetPosition().y else: val = eval('self.stick.Get%sPosition()' % self.token) # # While we might be able to rely on a range of 0-FFFFFF on Win, that might # not be true of all drivers on all platforms. Thus, calc the actual full # range first. # if min < 0: max += abs(min) val += abs(min) min = 0 range = float(max - min) # # The relative value is used by the derived wx.Gauge since it is a # positive-only control. # relative = 0 if range: relative = int( val / range * 1000) # # Pass both the raw and relative values to the derived Gauge # self.bar.Update(relative, val) def alwaysTrue(self): # a dummy method used for X and Y axis. return True #---------------------------------------------------------------------------- class AxisPanel(wx.Panel): # # Contained herein is a panel that offers a graphical display # of the levels for all axes supported by wx.Joystick. If # your system doesn't have a particular axis, it will be # 'dummied' for transparent use. # def __init__(self, parent, stick): self.stick = stick # Defines labels and 'tokens' to identify each # supporte axis. axesList = [ ('X Axis ', 'X'), ('Y Axis ', 'Y'), ('Z Axis ', 'Z'), ('Rudder ', 'Rudder'), ('U Axis ', 'U'), ('V Axis ', 'V') ] # Contains a list of all axis initialized. self.axes = [] wx.Panel.__init__(self, parent, -1) sizer = wx.FlexGridSizer(3, 4, 1, 1) sizer.AddGrowableCol(1) sizer.AddGrowableCol(3) #---------------------------------------------------------------------------- # Go through the list of labels and tokens and add a label and # axis display to the sizer for each. for label, token in axesList: sizer.Add(Label(self, label), 0, wx.ALL | wx.ALIGN_RIGHT, 2) t = Axis(self, token, self.stick) self.axes.append(t) sizer.Add(t, 1, wx.ALL | wx.EXPAND | wx.ALIGN_LEFT, 2) #---------------------------------------------------------------------------- self.SetSizer(sizer) sizer.Fit(self) wx.CallAfter(self.Update) def Calibrate(self): for i in self.axes: i.Calibrate() def Update(self): for i in self.axes: i.Update()