Forum Archive

Basic Pythonista Scene Button?

Vile

Hi, I was trying to make a basic button in the middle of a blank black screen, which did something when touched.

I’d like to make it play a sound when the button is touched, but nothing happens.

Any help with this would be greatly appreciated, thanks!

Here’s a link to my code: here - hope this link works

Vile

Update: I’ve finally got the button to work!

Basically the issue was, that the touches can only be used on the scene level, so the indentation of the touch functions matter a lot.

The working code is here! :)

ccc

These links make me nervous from a security perspective so I created the following snippet...

from urllib.parse import unquote

text = """pythonista3://?exec=from%20scene%20import%20*%0Aimport%20ui%0Aimport%20sound%0Aimport%20os%0A%0Ax,y%20%3D%20get_screen_size%28%29%0A%0Abutton_font%20%3D%20%28%27Avenir%20Next%27,%2020%29%0A%0A%0Aclass%20ButtonNode%20%28SpriteNode%29:%0A%09def%20__init__%28self,%20title,%20args,%20kwargs%29:%0A%09%09SpriteNode.init%28self,%20%27pzl:Button1%27,%20args,%20**kwargs%29%0A%09%09button_font%20%3D%20%28%27Avenir%20Next%27,%2020%29%0A%09%09self.title_label%20%3D%20LabelNode%28title,%20font%3Dbutton_font,%20color%3D%27black%27,%20position%3D%280,1%29,%20parent%3Dself%29%0A%09%09self.title%20%3D%20title%0A%0Aclass%20button_scene%28Scene%29:%0A%09def%20setup%28self%29:%0A%09%09self.background_color%20%3D%20%27black%27%0A%09%09self.btn%20%3D%20ButtonNode%28%27dnndjdjdj%27%29%0A%09%09self.btn.position%20%3D%20%28x/2,y/2%29%0A%09%09self.add_child%28self.btn%29%0A%0A%09def%20touch_began%28self,%20touch%29:%0A%09%09self.handle_touch%28touch%29%0A%0A%09def%20touch_moved%28self,%20touch%29:%0A%09%09pass%0A%0A%09def%20touch_ended%28self,%20touch%29:%0A%09%09pass%0A%0A%09def%20handle_touch%28self,%20touch%29:%0A%09%09if%20touch.location%20in%20self.btn.frame:%0A%09%09%09sound.play_effect%28%278ve:8ve-tap-percussive%27%29%0A%0Aif%20__name__%20%3D%3D%20%27__main__%27:%0A%09run%28button_scene%28%29,%20orientation%3DLANDSCAPE,%20frame_interval%3D1,%20anti_alias%3DFalse,%20show_fps%3DTrue,%20multi_touch%3DTrue%29%0A"""

print(unquote(text))

Which generates for the text of the second URL above:

pythonista3://?exec=from scene import *
import ui
import sound
import os

x,y = get_screen_size()

button_font = ('Avenir Next', 20)


class ButtonNode (SpriteNode):
    def __init__(self, title, args, kwargs):
        SpriteNode.init(self, 'pzl:Button1', args, **kwargs)
        button_font = ('Avenir Next', 20)
        self.title_label = LabelNode(title, font=button_font, color='black', position=(0,1), parent=self)
        self.title = title

class button_scene(Scene):
    def setup(self):
        self.background_color = 'black'
        self.btn = ButtonNode('dnndjdjdj')
        self.btn.position = (x/2,y/2)
        self.add_child(self.btn)

    def touch_began(self, touch):
        self.handle_touch(touch)

    def touch_moved(self, touch):
        pass

    def touch_ended(self, touch):
        pass

    def handle_touch(self, touch):
        if touch.location in self.btn.frame:
            sound.play_effect('8ve:8ve-tap-percussive')

if __name__ == '__main__':
    run(button_scene(), orientation=LANDSCAPE, frame_interval=1, anti_alias=False, show_fps=True, multi_touch=True)

This appears to be safe to me but could the text of one of these URLs be modified to do something far more dangerous?

mikael

@ccc, you’re right, this is pretty scary. Any way to whitelist what Pythonista will execute with a URL?

mikael

@Vile, if you are going to have a lot of buttons or similar, just a reminder that you can include components from the ui module in a scene.

JonB

The pythonista3 executable urls let you review the code before it executes, or gives you an option iirc to save without executing..

So reasonably safe.

cvp

@JonB options are cancel or run, not save but, of course, you could always copy/paste the listed code.

Vile

@ccc lol I’m too noob to be a hacker and do weird stuff to URLs so don’t worry (although this is probably what a hacker would say) XD

Vile

@mikael, could you give an example of using the ui module to make 4 buttons, which each play a different sound, in 4 different corners of the screen?

Rather than making a canvas, I’d like to use the size of the screen: x/4,y/4 to position the bottom left button, for example, and x/4,y/4*3 for the top left, etc, because I don’t want to have to make custom adjustments for different device screen sizes and ratios.

JonB

you can use flex to keep the buttons sized properly for different devices.

example

Vile

@JonB, thanks for the example!

However, I plan on using the buttons in a game, and I don’t think that the ui module is good for that.

This is because in all the ui examples I’ve seen, there’s an annoying white bar at the top of the screen with an X on it.

In contrast, when I set a background colour in the scene module, it looks neat and covers the whole screen.

Is there a way of getting rid of the white thing when using the ui module? I don’t think it’s artistically appropriate for games.

ccc

View.present(hide_title_bar=True)

mikael

@Vile, you can very well make a game using either ui or scene module, hide extra bars etc. To me ui module works better, but scene does have more game-like mechanics (e.g. better out-of-the-box support for animations).

As an example of combining the two worlds:

import scene
import ui
import sound

class MyScene (scene.Scene):
  def setup(self):
    self.ship = scene.SpriteNode('spc:PlayerShip1Orange')
    self.ship.position = self.size / 2
    self.add_child(self.ship)

    btn = ui.Button(
      title='Make sound',
      tint_color='white',
      background_color='blue',
      action=self.make_sound
    )
    frm = btn.frame
    bnds = self.view.bounds
    btn.frame = frm.inset(-8,-8)
    btn.frame = (
      bnds.width - btn.width - 8,
      bnds.height - btn.height - 8,
      btn.width,
      btn.height
    )
    btn.flex = 'RTBL'
    self.view.add_subview(btn)

  def make_sound(self, sender):
    sound.play_effect('arcade:Laser_1')

scene.run(MyScene())