It looks like you're failing to call initWithMenu...
self.menu=PyFR.MenuController.Menu("EyeTV",
[
self.recordings_menu,
self.MakeChannelsMenu(),
PyFR.MenuController.MenuItem("Enter EyeTV", self.StartETV),
PyFR.MenuController.MenuItem("Program guide",
self.StartETVGuide)
# ,PyFR.MenuController.MenuItem("Comskip
off", ShowGuide_MenuHandler)
# ,PyFR.MenuController.MenuItem("Comskip
off", ShowGuide_MenuHandler)
# ,PyFR.MenuController.MenuItem("Option
dialog", testOptionDialogTest, "Text test")
# ,PyFR.MenuController.MenuItem("Text
test", TestText_MenuHandler, "Text test")
])
ac=PyFR.MenuController.MenuController.initWithMenu_(self, self.menu)
I have the main menu up and running in FrontRow, but I can't seem to
get submenus to work properly...
When I hit return / enter on the menu selection, the screen clears,
and is competely blank... And never goes anywhere...
No error message is in the console, and Frontrow does not error out...
I'm assuming where getting into a endless loop somehow...
Any suggestions?
- Benjamin
def DeviceOptionsMenuHandler(self, controller, data):
log("RecordingOptionsMenuHandler, controller is %s" % str(controller))
log (data)
# if we return true, we'll pop the controller and back up past the
option dialog
return True
def GetDeviceOptionsMenu(self, name):
display_items= [
PyFR.MenuController.MenuItem(title = "Turn On",
func=self.DeviceOptionsMenuHandler, arg=(name,0), metadata_func=None,
smalltext = False),
PyFR.MenuController.MenuItem(title = "Turn Off", func=
self.DeviceOptionsMenuHandler, arg=(name,1), metadata_func=None,
smalltext = False),
PyFR.MenuController.MenuItem(title = "Cancel", func=
self.DeviceOptionsMenuHandler, arg=(name,2), metadata_func=None,
smalltext = False)
]
menu=PyFR.MenuController.Menu(page_title = name, items=display_items)
dlg=PyFR.MenuController.MenuController.initWithMenu_(self, menu)
self.CurrentOptionsMenu = dlg
return dlg
def DeviceOptionsMenu(self,controller, name):
log("in Device options dialog")
#log (name)
#name = name.split (" -")[0]
dlg=self.GetDeviceOptionsMenu(name)
# return dlg
return controller.stack().pushController_(dlg)
def get_device_list ( self ):
indigo_connection = Indigo_Connect
(indigoconn.kConn_ClientWebServer, "Security", AuthenticateConnection,
1176, log, log)
indigo_connection.Connect ( 'schollnick.homeip.net')
devicelist = indigo_connection.Request_GetDeviceList ()
dev_list = []
for x in devicelist:
if x.typeSupportsDim or x.typeSupportsOnOff:
dev_list.append ( "%s - %s" % (x.name, x.deviceState) )
indigo_connection.DestroyIndigoConnection()
return dev_list
def init (self):
self.display_items= []
dev_list = self.get_device_list ()
for x in dev_list:
#print device, state
self.display_items.append ( PyFR.MenuController.MenuItem(title=x,
func=self.DeviceOptionsMenu, arg=x, metadata_func=None, smalltext =
False) )
self.FRMenu = PyFR.MenuController.Menu ( page_title = "Home Status",
items=self.display_items)#
self.ac = PyFR.MenuController.MenuController.initWithMenu_ (self,
self.FRMenu)
# FRMenu = PyFR.MenuController.Menu ( page_title = "Test Title",
items=display_items)#
# PyFR.MenuController.MenuController.Menu ( FRMenu)
#dlg=PyFR.MenuController.MenuController.Menu( FRMenu)
return self.ac
On Mon, May 5, 2008 at 12:22 PM, Benjamin Schollnick
<bscho...@gmail.com> wrote:
> dlg=PyFR.MenuController.MenuController.initWithMenu_(self, menu)
At first glance, I'd try:
dlg=PyFR.MenuController.alloc().MenuController.initWithMenu_(self, menu)
-Jon
-Jon
On Mon, May 5, 2008 at 12:22 PM, Benjamin Schollnick
<bscho...@gmail.com> wrote:
>
This submenu issue is driving me a little batty... I'll email with
the console log tomorrow morning....
- Benjamin
Did you try adding in the alloc() call like I suggested?
-Jon
On Mon, May 5, 2008 at 9:09 PM, Benjamin Schollnick
- Benjamin
Here's the log entries from the console log.
5/5/08 4:23:45 PM Front Row[30375] PyeTV: connecting to Indigo server
5/5/08 4:23:46 PM Front Row[30375] PyeTV: disconnecting from Indigo
server
5/5/08 4:23:48 PM Front Row[30375] PyeTV: in Device options dialog
5/5/08 4:23:48 PM Front Row[30375] PyeTV: RecordingOptionsMenuHandler,
controller is <MyMenuController: 0xc382680> labels: Home Status
5/5/08 4:23:48 PM Front Row[30375] PyeTV: B02
5/5/08 4:23:48 PM Front Row[30375] PyeTV: Return from
GetDeviceOptionsMenu
5/5/08 4:23:57 PM com.apple.launchd[130] (com.apple.RemoteUI[30375])
Exited: Terminated
And the current code base...
As we can see from the console log, Frontrow is reaching at least the
DeviceOptionsMenu return statement...
But I can't make heads or tails of two bits...
1) I can't tell what the controller stack / push controller actually
does... I haven't found any documentation on that...
2) Nor have I found any documentation on the
(DeviceOptionsMenuHandler) MenuHandler code... I am working on the
assumption that the data that is based to the MenuHandler is the Args
from the MenuItem...
Any suggestions?
I do plan to create a small sample for inclusion with the SDK once I
have figured all this out...
- Benjamin
class MyMenuController ( PyFR.MenuController.MenuController):
def DeviceOptionsMenuHandler(self, controller, data):
log("RecordingOptionsMenuHandler, controller is %s" % str(controller))
log (data)
# if we return true, we'll pop the controller and back up past the
option dialog
return True
def GetDeviceOptionsMenu(self, name):
display_items= [
PyFR.MenuController.MenuItem(title = "Turn On",
func=self.DeviceOptionsMenuHandler, arg=(name,0), metadata_func=None,
smalltext = False),
PyFR.MenuController.MenuItem(title = "Turn Off",
func=self.DeviceOptionsMenuHandler, arg=(name,1), metadata_func=None,
smalltext = False),
PyFR.MenuController.MenuItem(title = "Cancel",
func=self.DeviceOptionsMenuHandler, arg=(name,2), metadata_func=None,
smalltext = False)
]
menu=PyFR.MenuController.Menu(page_title = name, items=display_items)
dlg=PyFR.MenuController.MenuController.initWithMenu_(self, menu)
self.CurrentOptionsMenu = dlg
return dlg
def DeviceOptionsMenu(self,controller, name):
log("in Device options dialog")
log("RecordingOptionsMenuHandler, controller is %s" % str(controller))
#
# log ( str(name[0]) )
# log ( str(name[1]) )
name = name.split ("-")[0]
log ( name )
dlg=self.GetDeviceOptionsMenu(name)
log ("Return from GetDeviceOptionsMenu")
# return dlg
return controller.stack().pushController_(dlg)
def get_device_list ( self ):
indigo_connection = Indigo_Connect
(indigoconn.kConn_ClientWebServer, "Security", AuthenticateConnection,
1176, log, log)
indigo_connection.Connect ( 'schollnick.homeip.net')
devicelist = indigo_connection.Request_GetDeviceList ()
dev_list = []
for x in devicelist:
if x.typeSupportsDim or x.typeSupportsOnOff:
dev_list.append ( "%s - %s" % (x.name, x.deviceState) )
indigo_connection.DestroyIndigoConnection()
return dev_list
def init (self):
self.display_items= []
dev_list = self.get_device_list ()
for x in dev_list:
#print device, state
self.display_items.append ( PyFR.MenuController.MenuItem(title=x,
func=self.DeviceOptionsMenu, arg=x, metadata_func=None, smalltext =
False) )
self.FRMenu = PyFR.MenuController.Menu ( page_title = "Home Status",
items=self.display_items)#
self.ac = PyFR.MenuController.MenuController.initWithMenu_ (self,
self.FRMenu)
# FRMenu = PyFR.MenuController.Menu ( page_title = "Test Title",
items=display_items)#
# PyFR.MenuController.MenuController.Menu ( FRMenu)
#dlg=PyFR.MenuController.MenuController.Menu( FRMenu)
return self.ac
I'll be trying to add submenu's to the DynamicMenuController version
later today....
- Benjamin
On May 5, 2008, at 3:42 PM, Jon Christopher wrote:
>
But I must be misunderstanding the comment in DynamicMenuItem //
Dynamic Menu.
# simple container class for a menu, elements of the items list may
contain menu items or another Menu instance for submenus
#class DynamicMenu:
This to me, implies that if I pass a DynamicMenu as an item to a
DynamicMenu, that it should create a submenu...
But in Practice, I am getting:
5/6/08 1:29:22 PM Front Row[37083] TypeError: 'NoneType' object is not
callable
Which only makes sense if it was attempting to run the function, not
display a submenu....
I have tried a few different ways (see comments in code)... But with
no luck...
Anyone use DynamicMenu to create submenus?
- Benjamin
class MyMenuController
( PyFR.DynamicMenuController.DynamicMenuController):
def on_off_cancel_menu ( self, identifier):
new_menu = PyFR.DynamicMenuController.DynamicMenu (page_title =
identifier, items = [])
new_menu.AddItem ( PyFR.DynamicMenuController.DynamicMenuItem (title
= "Turn On", func=None, arg=identifier, metadata_func=None, folder =
False) )
new_menu.AddItem ( PyFR.DynamicMenuController.DynamicMenuItem (title
= "Turn Off", func=None, arg=identifier, metadata_func=None, folder =
False) )
new_menu.AddItem ( PyFR.DynamicMenuController.DynamicMenuItem (title
= "Cancel", func=None, arg=identifier, metadata_func=None, folder =
False) )
return new_menu
def get_device_list ( self, FRMenu ):
indigo_connection = Indigo_Connect
(indigoconn.kConn_ClientWebServer, "Security", AuthenticateConnection,
1176, log, log)
indigo_connection.Connect ( 'schollnick.homeip.net')
devicelist = indigo_connection.Request_GetDeviceList ()
for x in devicelist:
if x.typeSupportsDim or x.typeSupportsOnOff:
FRMenu.AddItem ( PyFR.DynamicMenuController.DynamicMenuItem (title
= "%s - %s" % (x.name, x.deviceState), func=None, arg=None,
metadata_func=None, folder = True) )
#
# This locks frontrow... But is how I read DynamicMenu's
Comment....
#FRMenu.AddItem ( PyFR.DynamicMenuController.DynamicMenuItem
(title = self.on_off_cancel_menu(x.name), func=None, arg=None,
metadata_func=None, folder = True) )
#
# Alternatively
# FRMenu.AddItem ( PyFR.DynamicMenuController.DynamicMenuItem
(title = "test2", func=self.on_off_cancel_menu(self, x.name),
arg=None, metadata_func=None, folder = True) )
# returns: 5/6/08 1:39:56 PM Front Row[37149] AttributeError:
DynamicMenu instance has no __call__ method
indigo_connection.DestroyIndigoConnection()
return FRMenu#dev_list
def init (self):
self.FRMenu = PyFR.DynamicMenuController.DynamicMenu ( page_title =
"Device Status", items=[])
self.FRMenu = self.get_device_list ( self.FRMenu )
log ( "Returned from Device List")
self.FrontrowMainController =
PyFR.DynamicMenuController.DynamicMenuController.initWithMenu_
( self, menu=self.FRMenu )
log ("After DynamicMenuController Assignment")
return self.FrontrowMainController
See PyFR/FileBrowser.py for a decent example of creating submenus.
Cheers,
Jon
That comment is probably bogus, I agree.. Probably that what I was
planning on doing, where you could do something like:
menu.AddItem( MenuItem() )
menu.AddItem( MenuItem() )
menu.AddItem( Menu() )
But it may not have worked out that way..
Looking at the FileBrwose, what I think you need to do is to wait for
the user to select something, and then push the new menu out then.
I plan on getting back into coding this again soon.. I'm getting the
itch to write a real MythTV frontend, not just calling the
MythFrontend.app, which means I'll probably need more features in
FrontPython to support it...
--John
As far as I can tell, I am doing everything fine... But FrontRow is
not drawing the submenu...
I can hear it clicking underneath, but I can't see the secondary
window...
- Benjamin
class MyMenuController
( PyFR.DynamicMenuController.DynamicMenuController):
def on_off_cancel_menu ( self, menuItem):
log ( menuitem )
log ( menuitem.title )
self.on_off_menu = PyFR.DynamicMenuController.DynamicMenu
( page_title = "Change Device Status", items = [])
self.on_off_menu.AddItem
( PyFR.DynamicMenuController.DynamicMenuItem (title = "Turn On",
func=None, arg=None, metadata_func=None, folder = False) )
self.on_off_menu.AddItem
( PyFR.DynamicMenuController.DynamicMenuItem (title = "Turn Off",
func=None, arg=None, metadata_func=None, folder = False) )
self.on_off_menu.AddItem
( PyFR.DynamicMenuController.DynamicMenuItem (title = "Cancel
Changes", func=None, arg=None, metadata_func=None, folder = False) )
self.On_Off_Controller =
PyFR.DynamicMenuController.DynamicMenuController.initWithMenu_
( self, menu=self.on_off_menu )
return self.On_Off_Controller
def get_device_list ( self, FRMenu ):
indigo_connection = Indigo_Connect
(indigoconn.kConn_ClientWebServer, "Security", AuthenticateConnection,
1176, log, log)
indigo_connection.Connect ( 'schollnick.homeip.net')
devicelist = indigo_connection.Request_GetDeviceList ()
for x in devicelist:
if x.typeSupportsDim or x.typeSupportsOnOff:
FRMenu.AddItem ( PyFR.DynamicMenuController.DynamicMenuItem (title
= "%s - %s" % (x.name, x.deviceState), func=self.on_off_cancel_menu,
arg=None, metadata_func=None, folder = True) )
#FRMenu.AddItem ( PyFR.DynamicMenuController.DynamicMenuItem
(title = "test2", func=self.on_off_cancel_menu(self, x.name),
arg=None, metadata_func=None, folder = True) )
indigo_connection.DestroyIndigoConnection()
return FRMenu#dev_list
def init (self):
self.FRMenu = PyFR.DynamicMenuController.DynamicMenu ( page_title =
"Device Status", items=[])
self.FRMenu = self.get_device_list ( self.FRMenu )
log ( "Returned from Device List")
self.FrontrowMainController =
PyFR.DynamicMenuController.DynamicMenuController.initWithMenu_
( self, menu=self.FRMenu )
log ("After DynamicMenuController Assignment")
return self.FrontrowMainController
def __clicked(self, menuItem):
selectedFile = self.directory + '/' + menuItem.title
if menuItem.folder:
menuController =
FileBrowserController.alloc().initWithDirectory_( selectedFile )
self.stack().pushController_(menuController)
else:
self.fileSelected_( selectedFile )
Note that in the case where we're creating a new menu (i.e. the item
is a folder), we're calling self.stack().pushController_
I don't see that in your code.
I'm very open to suggestions...
- Benjamin
class MyMenuController
( PyFR.DynamicMenuController.DynamicMenuController):
def on_off_cancel_menu ( self, menuItem):
# log ( menuItem )
# log ( menuItem.title )
#log ( str(menuItem.title) )
self.on_off_menu = PyFR.DynamicMenuController.DynamicMenu
( page_title = "Change Device Status", items = [])
self.on_off_menu.AddItem
( PyFR.DynamicMenuController.DynamicMenuItem (title = "Turn On",
func=None, arg=None, metadata_func=None, folder = False) )
self.on_off_menu.AddItem
( PyFR.DynamicMenuController.DynamicMenuItem (title = "Turn Off",
func=None, arg=None, metadata_func=None, folder = False) )
self.on_off_menu.AddItem
( PyFR.DynamicMenuController.DynamicMenuItem (title = "Cancel
Changes", func=None, arg=None, metadata_func=None, folder = False) )
self.On_Off_Controller =
PyFR.DynamicMenuController.DynamicMenuController.initWithMenu_
( self, menu=self.on_off_menu )
self.willBePushed()
self.stack().pushController_(self.On_Off_Controller) #Also tried
self.FrontRowMainController as well...
#return self.On_Off_Controller
indigo_connection.DestroyIndigoConnection()
There were multiple errors in your version; case sensitivity issues,
a missing alloc() in your on_off_cancel_menu fn, an erroneous "self"
argument passed to an init function of a different class, etc.
I don't have indigo, so I hacked a separate get_device_list2 function
which just returns a list of dummy devices. WIth this, the submenu
does show up.
Activating a submenu item causes an error b/c no handler is provided
for what to do in that case, but it at least gets the submenu up and
working.
-Jon
On Tue, May 6, 2008 at 1:23 PM, Benjamin Schollnick
I think you also need alloc() in the on_off_cancel_menu:
> self.On_Off_Controller =
> PyFR
> .DynamicMenuController.DynamicMenuController.initWithMenu_( self,
> menu=self.on_off_menu )
SHould be:
> self.On_Off_Controller =
> PyFR
> .DynamicMenuController
> .DynamicMenuController.alloc().initWithMenu_( menu=self.on_off_menu )
Because you are creating a new Menu, not overriding the current one.
--John
>
--John
Other things you might investigate for your indigo plugin are:
BRIPv4AddressEntryControl and BRTextEntryControl.
You can get headers for those from running class-dump over
/System/Library/CoreServices/Front Row.app.
They might help with your servername/password issues. Of course,
you'd probably only want the user to do this once and save the
authentication, so it'd probably be better to just have your installer
script prompt for these values and store them (encoded, perhaps) in
/Library/Application Support/Indigo, and
have your plugin read and decrypt from there.
I recommend double-rot13 encryption for twice the security ;)
-Jon
Thank you greatly for your assistance... The submenu is now working....
I do have to write the submenu handler, but that's for later (today or
tomorrow)...
- Benjamin
Actually, I have already investigated using the Macintosh keychain to
store the server information, and username / password.
I'll have to create a frontend to store the information into the
keychain, but the storage of the information is as secure as the
keychain...
And Double-Rot 13 is a fantastic idea... I hear that Adobe used a
single Rot13 for PDF passwords... Pity they didn't go with Double the
security... |-)
- Benjamin
What's the best way to get a Dynamic Menu to refresh // Reflect a
change in the menu?
I've tried a few things, but with very limited success... The closest
example I found was FileBrowser, but that's just recurvsively creating
a new menu... Not showing anything changed...
I tried changing the items cache directly, but that didn't seem to
take....
Any suggestions?
- Benjamin
class MyMenuController
( PyFR.DynamicMenuController.DynamicMenuController):
def update_menu_item ( self, name, new_status):
# new_item = PyFR.DynamicMenuController.DynamicMenuItem (title = "%s
- %s" % (name, new_status), func=self.on_off_cancel_menu, arg=name,
metadata_func=None, folder = True) )
for x in range(0, len(self.FRMenu.items)):
#log (self.FRMenu.items[x].title)
if self.FRMenu.items[x].title.startswith ( name):
log ("Matches")
self.FRMenu.items[x].title == "%s - %s" % (name, new_status)
return
def on_off_handler ( self, menuItem):
name_of_device = menuItem.arg[1]
if menuItem.arg[0] == 0: # Turn On
indigo_connection = Indigo_Connect
(indigoconn.kConn_ClientWebServer, "Security", AuthenticateConnection,
1176, log, log)
indigo_connection.Connect ( 'schollnick.homeip.net')
indigo_connection.Device_Turn_On ( DeviceName = name_of_device )
indigo_connection.DestroyIndigoConnection ()
self.update_menu_item ( name_of_device, "On")
elif menuItem.arg[0] == 1: # Turn Off
indigo_connection = Indigo_Connect
(indigoconn.kConn_ClientWebServer, "Security", AuthenticateConnection,
1176, log, log)
indigo_connection.Connect ( 'schollnick.homeip.net')
indigo_connection.Device_Turn_Off ( DeviceName = name_of_device )
indigo_connection.DestroyIndigoConnection ()
self.update_menu_item ( name_of_device, "Off")
elif menuItem.arg[0] == 2: # Cancel
pass
#self.FRMenu = self.get_device_list ( self.FRMenu ) # try to refresh
FRMenu?
self.FrontrowMainController.willBePopped ()
# self.FRMenu
self.stack().pushController_ ( self.FrontrowMainController )
return True
def on_off_cancel_menu ( self, menuItem):
title = menuItem.arg # Name is passed to on_off_cancel Menu
on_off_menu = PyFR.DynamicMenuController.DynamicMenu( page_title =
"%s" % title, items = [])#menuItem.title, items = [])
on_off_menu.AddItem( PyFR.DynamicMenuController.DynamicMenuItem
(title = "Turn On",func=self.on_off_handler, arg=(0, title),
metadata_func=None, folder = False) )
on_off_menu.AddItem( PyFR.DynamicMenuController.DynamicMenuItem
(title = "Turn Off",func=self.on_off_handler, arg=(1, title),
metadata_func=None, folder = False) )
on_off_menu.AddItem( PyFR.DynamicMenuController.DynamicMenuItem
(title = "Cancel Changes", func=self.on_off_handler, arg=(2, title),
metadata_func=None, folder = False) )
On_Off_Controller
=
PyFR
.DynamicMenuController
.DynamicMenuController.alloc().initWithMenu_(on_off_menu)
self.stack().pushController_(On_Off_Controller)
def get_device_list ( self, FRMenu ):
indigo_connection = Indigo_Connect
(indigoconn.kConn_ClientWebServer, "Security", AuthenticateConnection,
1176, log, log)
indigo_connection.Connect ( 'schollnick.homeip.net')
devicelist = indigo_connection.Request_GetDeviceList ()
indigo_connection.DestroyIndigoConnection ()
for x in devicelist:
if x.typeSupportsDim or x.typeSupportsOnOff:
FRMenu.AddItem ( PyFR.DynamicMenuController.DynamicMenuItem (title
= "%s - %s" % (x.name, x.deviceState), func=self.on_off_cancel_menu,
arg=x.name, metadata_func=None, folder = True) )
#FRMenu.AddItem ( PyFR.DynamicMenuController.DynamicMenuItem
(title = "test2", func=self.on_off_cancel_menu(self, x.name),
arg=None, metadata_func=None, folder = True) )
if self.AppRunning("ComSkipper"):
os.system("/usr/bin/killall ComSkipper &")
self.CurrentOptionsMenu.ds.menu.items[3].layer.setTitle_("ComSkipper
[Off]") # deep magic
else:
os.system("/Library/Application\
Support/ETVComskip/ComSkipper.app/Contents/MacOS/ComSkipper &")
self.CurrentOptionsMenu.ds.menu.items[3].layer.setTitle_("ComSkipper
[On]") # deep magic
CurrentOptionsMenu.ds.refreshControllerForModelUpdate() *might* work, too.
-Jon