| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- #!/usr/bin/env python
- '''
- Demonstrate how a simple button mapping gui can be written
- '''
- from direct.showbase.ShowBase import ShowBase
- from direct.gui.DirectGui import (
- DGG,
- DirectFrame,
- DirectButton,
- DirectLabel,
- OkCancelDialog,
- DirectScrolledFrame)
- from panda3d.core import (
- VBase4,
- TextNode,
- Vec2,
- InputDevice,
- loadPrcFileData)
- # Make sure the textures look crisp on every device that supports
- # non-power-2 textures
- loadPrcFileData("", "textures-auto-power-2 #t")
- class App(ShowBase):
- def __init__(self):
- ShowBase.__init__(self)
- self.setBackgroundColor(0, 0, 0)
- # make the font look nice at a big scale
- DGG.getDefaultFont().setPixelsPerUnit(100)
- # a dict of actions and button/axis events
- self.gamepadMapping = {
- "Move forward":"Left Stick Y",
- "Move backward":"Left Stick Y",
- "Move left":"Left Stick X",
- "Move right":"Left Stick X",
- "Jump":"a",
- "Action":"b",
- "Sprint":"x",
- "Map":"y",
- "action-1":"c",
- "action-2":"d",
- "action-3":"e",
- "action-4":"f",
- "action-5":"g",
- "action-6":"h",
- "action-7":"i",
- "action-8":"j",
- "action-9":"k",
- "action-10":"l",
- "action-11":"m",
- }
- # this will store the action that we want to remap
- self.actionToMap = ""
- # this will store the key/axis that we want to asign to an action
- self.newActionKey = ""
- # this will store the label that needs to be actualized in the list
- self.actualizeLabel = None
- # The geometry for our basic buttons
- maps = loader.loadModel("models/button_map")
- self.buttonGeom = (
- maps.find("**/ready"),
- maps.find("**/click"),
- maps.find("**/hover"),
- maps.find("**/disabled"))
- # Create the dialog that asks the user for input on a given
- # action to map a key to.
- DGG.setDefaultDialogGeom("models/dialog.png")
- # setup a dialog to ask for device input
- self.dlgInput = OkCancelDialog(
- dialogName="dlg_device_input",
- pos=(0, 0, 0.25),
- text="Hit desired key:",
- text_fg=VBase4(0.898, 0.839, 0.730, 1.0),
- text_shadow=VBase4(0, 0, 0, 0.75),
- text_shadowOffset=Vec2(0.05, 0.05),
- text_scale=0.05,
- text_align=TextNode.ACenter,
- fadeScreen=0.65,
- frameColor=VBase4(0.3, 0.3, 0.3, 1),
- button_geom=self.buttonGeom,
- button_scale=0.15,
- button_text_scale=0.35,
- button_text_align=TextNode.ALeft,
- button_text_fg=VBase4(0.898, 0.839, 0.730, 1.0),
- button_text_pos=Vec2(-0.9, -0.125),
- button_relief=1,
- button_pad=Vec2(0.01, 0.01),
- button_frameColor=VBase4(0, 0, 0, 0),
- button_frameSize=VBase4(-1.0, 1.0, -0.25, 0.25),
- button_pressEffect=False,
- command=self.closeDialog)
- self.dlgInput.setTransparency(True)
- self.dlgInput.configureDialog()
- scale = self.dlgInput["image_scale"]
- self.dlgInput["image_scale"] = (scale[0]/2.0, scale[1], scale[2]/2.0)
- self.dlgInput["text_pos"] = (self.dlgInput["text_pos"][0], self.dlgInput["text_pos"][1] + 0.06)
- self.dlgInput.hide()
- # create a sample title
- self.textscale = 0.1
- self.title = DirectLabel(
- scale=self.textscale,
- pos=(base.a2dLeft + 0.05, 0.0, base.a2dTop - (self.textscale + 0.05)),
- frameColor=VBase4(0, 0, 0, 0),
- text="Button Mapping",
- text_align=TextNode.ALeft,
- text_fg=VBase4(1, 1, 1, 1),
- text_shadow=VBase4(0, 0, 0, 0.75),
- text_shadowOffset=Vec2(0.05, 0.05))
- self.title.setTransparency(1)
- # Set up the list of actions that we can map keys to
- # create a frame that will create the scrollbars for us
- # Load the models for the scrollbar elements
- thumbMaps = loader.loadModel("models/thumb_map")
- thumbGeom = (
- thumbMaps.find("**/thumb_ready"),
- thumbMaps.find("**/thumb_click"),
- thumbMaps.find("**/thumb_hover"),
- thumbMaps.find("**/thumb_disabled"))
- incMaps = loader.loadModel("models/inc_map")
- incGeom = (
- incMaps.find("**/inc_ready"),
- incMaps.find("**/inc_click"),
- incMaps.find("**/inc_hover"),
- incMaps.find("**/inc_disabled"))
- decMaps = loader.loadModel("models/dec_map")
- decGeom = (
- decMaps.find("**/dec_ready"),
- decMaps.find("**/dec_click"),
- decMaps.find("**/dec_hover"),
- decMaps.find("**/dec_disabled"))
- # create the scrolled frame that will hold our list
- self.lstActionMap = DirectScrolledFrame(
- # make the frame occupy the whole window
- frameSize=VBase4(base.a2dLeft, base.a2dRight, 0.0, 1.55),
- # make the canvas as big as the frame
- canvasSize=VBase4(base.a2dLeft, base.a2dRight, 0.0, 0.0),
- # set the frames color to white
- frameColor=VBase4(0, 0, 0.25, 0.75),
- pos=(0, 0, -0.8),
- verticalScroll_scrollSize=0.2,
- verticalScroll_frameColor=VBase4(0.02, 0.02, 0.02, 1),
- verticalScroll_thumb_relief=1,
- verticalScroll_thumb_geom=thumbGeom,
- verticalScroll_thumb_pressEffect=False,
- verticalScroll_thumb_frameColor=VBase4(0, 0, 0, 0),
- verticalScroll_incButton_relief=1,
- verticalScroll_incButton_geom=incGeom,
- verticalScroll_incButton_pressEffect=False,
- verticalScroll_incButton_frameColor=VBase4(0, 0, 0, 0),
- verticalScroll_decButton_relief=1,
- verticalScroll_decButton_geom=decGeom,
- verticalScroll_decButton_pressEffect=False,
- verticalScroll_decButton_frameColor=VBase4(0, 0, 0, 0),)
- # creat the list items
- idx = 0
- self.listBGEven = base.loader.loadModel("models/list_item_even")
- self.listBGOdd = base.loader.loadModel("models/list_item_odd")
- for key, value in self.gamepadMapping.items():
- item = self.__makeListItem(key, key, value, idx)
- item.reparentTo(self.lstActionMap.getCanvas())
- idx += 1
- # recalculate the canvas size to set scrollbars if necesary
- self.lstActionMap["canvasSize"] = (
- base.a2dLeft+0.05, base.a2dRight-0.05,
- -(len(self.gamepadMapping.keys())*0.1), 0.09)
- self.lstActionMap.setCanvasSize()
- def closeDialog(self, result):
- self.dlgInput.hide()
- if result == DGG.DIALOG_OK:
- # map the event to the given action
- self.gamepadMapping[self.actionToMap] = self.newActionKey
- # actualize the label in the list that shows the current
- # event for the action
- self.actualizeLabel["text"] = self.newActionKey
- # cleanup
- self.dlgInput["text"] ="Hit desired key:"
- self.actionToMap = ""
- self.newActionKey = ""
- self.actualizeLabel = None
- for bt in base.buttonThrowers:
- bt.node().setButtonDownEvent("")
- for bt in base.deviceButtonThrowers:
- bt.node().setButtonDownEvent("")
- taskMgr.remove("checkControls")
- def changeMapping(self, action, label):
- # set the action that we want to map a new key to
- self.actionToMap = action
- # set the label that needs to be actualized
- self.actualizeLabel = label
- # show our dialog
- self.dlgInput.show()
- # catch all button events
- for bt in base.buttonThrowers:
- bt.node().setButtonDownEvent("keyListenEvent")
- for bt in base.deviceButtonThrowers:
- bt.node().setButtonDownEvent("deviceListenEvent")
- self.setKeyCalled = False
- self.accept("keyListenEvent", self.setKey)
- self.accept("deviceListenEvent", self.setDeviceKey)
- # As there are no events thrown for control changes, we set up
- # a task to check if the controls got moved
- # This list will help us for checking which controls got moved
- self.controlStates = {None:{}}
- # fill it with all available controls
- for device in base.devices.get_devices():
- for ctrl in device.controls:
- if device not in self.controlStates.keys():
- self.controlStates.update({device: {ctrl.axis: ctrl.state}})
- else:
- self.controlStates[device].update({ctrl.axis: ctrl.state})
- # start the task
- taskMgr.add(self.watchControls, "checkControls")
- def watchControls(self, task):
- # move through all devices and all it's controls
- for device in base.devices.get_devices():
- for ctrl in device.controls:
- # if a control got changed more than the given puffer zone
- if self.controlStates[device][ctrl.axis] + 0.2 < ctrl.state or \
- self.controlStates[device][ctrl.axis] - 0.2 > ctrl.state:
- # set the current state in the dict
- self.controlStates[device][ctrl.axis] = ctrl.state
- # check which axis got moved
- if ctrl.axis == InputDevice.C_left_x:
- self.setKey("Left Stick X")
- elif ctrl.axis == InputDevice.C_left_y:
- self.setKey("Left Stick Y")
- elif ctrl.axis == InputDevice.C_left_trigger:
- self.setKey("Left Trigger")
- elif ctrl.axis == InputDevice.C_right_x:
- self.setKey("Right Stick X")
- elif ctrl.axis == InputDevice.C_right_y:
- self.setKey("Right Stick Y")
- elif ctrl.axis == InputDevice.C_right_trigger:
- self.setKey("Right Trigger")
- elif ctrl.axis == InputDevice.C_x:
- self.setKey("X")
- elif ctrl.axis == InputDevice.C_y:
- self.setKey("Y")
- elif ctrl.axis == InputDevice.C_trigger:
- self.setKey("Trigger")
- elif ctrl.axis == InputDevice.C_throttle:
- self.setKey("Throttle")
- elif ctrl.axis == InputDevice.C_rudder:
- self.setKey("Rudder")
- elif ctrl.axis == InputDevice.C_hat_x:
- self.setKey("Hat X")
- elif ctrl.axis == InputDevice.C_hat_y:
- self.setKey("Hat Y")
- elif ctrl.axis == InputDevice.C_wheel:
- self.setKey("Wheel")
- elif ctrl.axis == InputDevice.C_accelerator:
- self.setKey("Acclerator")
- elif ctrl.axis == InputDevice.C_brake:
- self.setKey("Break")
- return task.cont
- def setKey(self, args):
- self.setKeyCalled = True
- if self.dlgInput.buttonList[0].guiItem.getState() == 1:
- # this occurs if the OK button was clicked. To prevent to
- # always set the mouse1 event whenever the OK button was
- # pressed, we instantly return from this function
- return
- self.dlgInput["text"] = "New event will be:\n\n" + args
- self.newActionKey = args
- def setDeviceKey(self, args):
- if not self.setKeyCalled:
- self.setKey(args)
- self.setKeyCalled = False
- def __makeListItem(self, itemName, action, event, index):
- def dummy(): pass
- if index % 2 == 0:
- bg = self.listBGEven
- else:
- bg = self.listBGOdd
- item = DirectFrame(
- text=itemName,
- geom=bg,
- geom_scale=(base.a2dRight-0.05, 1, 0.1),
- frameSize=VBase4(base.a2dLeft+0.05, base.a2dRight-0.05, -0.05, 0.05),
- frameColor=VBase4(1,0,0,0),
- text_align=TextNode.ALeft,
- text_scale=0.05,
- text_fg=VBase4(1,1,1,1),
- text_pos=(base.a2dLeft + 0.3, -0.015),
- text_shadow=VBase4(0, 0, 0, 0.35),
- text_shadowOffset=Vec2(-0.05, -0.05),
- pos=(0.05, 0, -(0.10 * index)))
- item.setTransparency(True)
- lbl = DirectLabel(
- text=event,
- text_fg=VBase4(1, 1, 1, 1),
- text_scale=0.05,
- text_pos=Vec2(0, -0.015),
- frameColor=VBase4(0, 0, 0, 0),
- )
- lbl.reparentTo(item)
- lbl.setTransparency(True)
- buttonScale = 0.15
- btn = DirectButton(
- text="Change",
- geom=self.buttonGeom,
- scale=buttonScale,
- text_scale=0.25,
- text_align=TextNode.ALeft,
- text_fg=VBase4(0.898, 0.839, 0.730, 1.0),
- text_pos=Vec2(-0.9, -0.085),
- relief=1,
- pad=Vec2(0.01, 0.01),
- frameColor=VBase4(0, 0, 0, 0),
- frameSize=VBase4(-1.0, 1.0, -0.25, 0.25),
- pos=(base.a2dRight-(0.898*buttonScale+0.3), 0, 0),
- pressEffect=False,
- command=self.changeMapping,
- extraArgs=[action, lbl])
- btn.setTransparency(True)
- btn.reparentTo(item)
- return item
- app = App()
- app.run()
|