PDA

View Full Version : FAO Rob and Tim: Restoring ListManager Pages...



NeoMorph
November 20th, 2007, 03:48 PM
OK... I know it's another ListManager problem *groan* but I've been sitting on this one for a while along with several others. The others I've sorted on my own but this one had me stumped until tonight

This ListManager is looking at folders that hold my music. It works drilling down but whenever I drill back up I always jump to page 1. Now this is how LM works I know but I wanted for it to remember where I was when I opened a folder.

That sounds a little confusing so I'll do a little example.

My music is sorted into Artist-> Album->Songs... Now if I scroll down to page 30 and open the directory "Siobhan Donaghy" I realise I miss-clicked and opened Shakira instead. I click the ".." to go back to the previous directory but now instead of being of being on page 30 I'm back on page 1. Saving the location where I was before I opened the folder should be possible and store it in a table corresponding to the depth.

Now I could store the correct LM.topMost value but I couldn't figure where in the code to reset the topMost value. Nothing seemed to work. So in the LM:OnPaint section I added a print and found something weird... it appears to paint the entire list twice which doesn't seem right (another bug maybe?). I was trying to set the topMost after the first paint cycle and the second cycle was overriding it.

So I made it count how many times it had painted the entire list and lo and behold if I made it do the reset after the second repaint it actually works. I then thought "Oops... what if it is actually a bug and Promixis doesn't know about it as it isn't an easily visible bug?"

So even though I have it working I thought you better have a look at the Listmanager code if it's repeating itself.

I still have one little bug in my code though - When I open a sub-folder and then come back up any empty slots in ListManager have lost their invisible status. I think it's seeing page 1 for the missing slots still (and because page 1 has all the slots being used it thinks it should display them all). It may be a symptom of the double painting but I'm really not sure here.

P.S. Oh and Tim please add the ability to copy from the Interactive Lua Console... I wanted to copy from the console to show you what I meant here but couldn't because it wouldn't let me.

NeoMorph
November 20th, 2007, 04:30 PM
OK... Sort of found how to hide the extra slot... I have to do another LM:RefreshList() in the Interactive Lua Console after everything is displayed but for some reason if I do it in the code it doesn't appear to work... I need to add a timer to wait long enough to get it to work which doesn't sound right. Is there some trigger that fires when the LM has finished painting that I could use to trigger a final refresh to hide those slots (but of course I'd have to set some kind of flag to have it only fire once or it would end up with it going into a refresh loop)

Obviously something isn't quite right with my code or LM itself. At one stage I had it in one hell of an infinite refresh loop (that was my code because I reset the test flag AFTER the refresh command so it wasn't getting set heh).

I wish I could show you my (crappy) code but you would need a specifically modded XBOX to get it to work. I'll have to have a think on how code up a dummy test to show you what is going on because something is going banananananananananananananas (that's the darn refresh loop again lol). It works (ie returns to the correct page when you hit the "..") except for the fact of the double painting and the empty slots not being hidden properly unless you do a manual LM:RefreshList().

Rob H
November 21st, 2007, 01:55 AM
Post the code anyway and I'll take a look.

I do something very similar to this for LDJ2 using a Stack object

NeoMorph
November 21st, 2007, 01:09 PM
Here's the ListManager code I'm using currently which is giving me problems...


ChannelManager = ListManager:New("xbmc", 14, Info)
ChannelManager.OnPressed = function(ChannelManager, index)

-- This little piece of code keeps track (hopefully) where you were when you open a folder

if Info[index].Title ~= ".." then
-- Store Current TopMost as it's a folder selection and not a parent directory request
TopMostDepth = TopMostDepth + 1
TopMostLastReading = ChannelManager.topMost
TopMostHistory[TopMostDepth] = TopMostLastReading
TopMostSurfacing = false
else
TopMostSurfacing = true -- because it's a parent directory request we need some way to trigger it...
PaintCount = 0 -- this is because for some reason listmanager paints twice and we need to count it...
end

-- Each ListManager button sets the ActionType variable so I can determine what to do
if ActionType=="select" then

if Info[index].Action == "queue" or Info[index].Action == "NoAction" then

-- Change from seperate Actions in Girder to a single XBMCcommand
--NetRemote.ExecuteAction(-1, 0, 1, "XBMC-Select("..Info[index].ID..")")
NetRemote.ExecuteAction(-1, 0, 1, "XBMCcommand(select:"..Info[index].ID..")")


print("==== ",Info[index].Action)
SetListmanagerHeading(Info[index].Title)
else
NetRemote.ExecuteAction(-1, 0, 1, "XBMC-SelectPlaylist("..Info[index].ID..")")
end
elseif ActionType=="action" then
if Info[index].Action == "queue" then
NetRemote.ExecuteAction(-1, 0, 1, "XBMC-Queue("..Info[index].ID..")")
NetRemote.SetVariable("XBMC.Status"," Added "..Info[index].Title.." to playlist")
elseif XBMCtabXaction[index] == "unque" then

nTopMost = ChannelManager.topMost
NetRemote.ExecuteAction(-1, 0, 1, "XBMC-Remove("..Info[index].ID..")")
end
elseif ActionType=="List" then
NetRemote.ExecuteAction(-1, 0, 1, "XBMC-List("..Info[index].ID..")")
elseif ActionType=="Remove" then
NetRemote.ExecuteAction(-1, 0, 1,Remove[index])
end

end


ChannelManager :UpdateEntries(Info)
ChannelManager.OnPaint = function(ChannelManager, entry, index)
NetRemote.SetVariable('ID.' .. index, (entry and entry.ID) or '')
NetRemote.SetVariable('Action.' .. index, (entry and entry.Action) or '')
NetRemote.SetVariable('Title.' .. index, (entry and entry.Title) or '')
NetRemote.SetVariable('Artist.' .. index, (entry and entry.Artist) or '')
NetRemote.SetVariable('Album.' .. index, (entry and entry.Album) or '')
NetRemote.SetVariable('TrackNo.' .. index, (entry and entry.TrackNo) or '')
print("--- ".. index .. " ---")
if index==14 then
print("> Paint Completed")
PaintCount = PaintCount + 1

-- Tried this but it doesn't work damnit... what next?
if HideEmptySlots == true then
HideEmptySlots = false
ChannelManager:RefreshList()
print("Hide the empty slots by refreshing")
end

end

if ChannelManager.topMost ~= TopMostHistory[TopMostDepth] and TopMostSurfacing == true and index==14 and PaintCount == 2 then
print("Surfacing... ", ChannelManager.topMost , TopMostHistory[TopMostDepth])
HideEmptySlots = true
print("==============")
ChannelManager.topMost = TopMostHistory[TopMostDepth]
ChannelManager:RefreshList()

TopMostDepth = TopMostDepth - 1
TopMostSurfacing = false
HideEmptySlots = true
end
end

Excuse the number of print statement... they are the only way I can figure out what's going on.

There are two listmanager buttons (Title and Queue/Unqueue) and 14 rows. The buttons have a Lua action before the LMAuto which states ...
ActionType="select"
... for the Title buttons and ...

ActionType="action"
... for the Queue/UnQueue button. Probably not the right way but it works ;).

Thanks for looking at this Rob.

Rob H
November 21st, 2007, 02:13 PM
Okay, I'm a little confused why you're calling RefreshList() from within OnPaint

And I also don't understand the logic of HideEmptySlots.

If a slot is empty, then in the OnPaint method you should find that entry is nil.

NeoMorph
November 21st, 2007, 02:46 PM
That's the problem Rob... it's not working right and why I tried the HideEmptySlots method that I did.

OK... If I go to the last page and I have 13 rows with data in them the 14 slot is hidden. Great.

http://www.neomorph.net/promixis/HiddenSlotProblem-1.png

Now I select, say item 5...

http://www.neomorph.net/promixis/HiddenSlotProblem-2.png

I then hit the ".." button to go back to the page of data which will have 13 rows of data in them..

http://www.neomorph.net/promixis/HiddenSlotProblem-3.png

Now line 14 which has no data in it has appeared! Huh? Note the entry count ("55 entries" shown below the list) hasn't changed so it's not a ghost entry.


I then go to the Interactive Lua Console and type...
ChannelManager:RefreshList()

http://www.neomorph.net/promixis/HiddenSlotProblem-4.png

... and lo and behold the empty row vanishes like it should do. So I added that code that now waits until it's finished painting the list and then does an extra RefreshList() at the end to hopefully hide the extra slot. But it doesn't work hence why I posted this thread.

Try adding a print("--- ".. index .. " ---") in an OnPrint of one of your panels and watch what it prints out in the lua console when it paints your listmanager output. You will see that what should be a single paint actually paints the whole list twice. I'm getting more and more convinced this is a bug in the LM paint code Rob.

Rob H
November 21st, 2007, 03:56 PM
Okay, so what is responsible for showing and hiding the frames in that loop in your CCF? ie what state variable is being monitored?

Great looking CCF by the way!

NeoMorph
November 21st, 2007, 08:25 PM
Sorry... Should have included it. It's a selected state (ie not lua)



Default - Hidden
State 1

xbmc_<LoopIndex>.Visible is 1

Not sure it can be any simpler than that...

Glad you like the panel... It's taking longer to work on atm becuase like normal when the weather gets colder my pain gets worse and I have to take more darn painkillers and they turn my brain to mush so when I'm not coding I can still work on the graphics.

I'm still working on the album cover page (I'm trying to make it a flipover so it shows the front of the case and then tapping it flips it over... Unfortunately I've been trying to do it in Flash and failing... dismally. Wrong time of year for me to learn new stuff unfortunately).

NeoMorph
November 21st, 2007, 08:26 PM
Sorry... Should have included it. It's a selected state (ie not lua)



Default - Hidden
State 1

xbmc_<LoopIndex>.Visible is 1

Not sure it can be any simpler than that...

Glad you like the panel... It's taking longer to work on atm becuase like normal when the weather gets colder my pain gets worse and I have to take more darn painkillers and they turn my brain to mush so when I'm not coding I can still work on the graphics.

I'm still working on the album cover page (I'm trying to make it a flipover so it shows the front of the case and then tapping it flips it over... Unfortunately I've been trying to do it in Flash and failing... dismally. Wrong time of year for me to learn new stuff I guess).

It's 5:27am and I'm still awake... all due to the sodding pain! Come on medical science... Invent the whole body transplant already! :)

Rob H
November 22nd, 2007, 12:56 AM
What's the range of values of index as shown by your print call?

NeoMorph
November 22nd, 2007, 05:32 AM
It goes 1 - 14 and then 1 - 14 again for each update.

Rob H
November 22nd, 2007, 01:38 PM
Hang on, how are you updating Info?

NeoMorph
November 22nd, 2007, 09:37 PM
Girder...

Girder handles all the calls to the xbox (via web urls) and grabs and formats the information.

The problem isn't there Rob... the information hasn't changed between the time I hit return up a level and have the blank entry appear and when I hit ChannelManager:RefreshList() in the Lua console. There is the same 55 entries (just check the images and you will see at the bottom of the list a summery of how many items are in Info).

This is why I said it would be difficult for you to see without having an modded xbox with XBMC to play with. I think I need to create a demo that will show what is happening and at the moment that is impossible (brain is too befuddled plus I have had a migraine for the past couple of days which is making me feel awful what with the migraine itself and the anti-migraine drugs making me feel icky). Once I feel well enough I'll put a demo together and maybe you'll see what I mean about it being Listmanager not hiding the blank entry correctly... maybe I'll find it's my code that's at fault... I just don't have any ideas at the moment but something is pear shaped.

Just as a matter of interest, why does listmanager paint the list twice?

Rob H
November 23rd, 2007, 07:42 AM
Well, it doesn't paint twice for me - most likely it's because of your extra call to RefreshList within the OnPaint

NeoMorph
November 24th, 2007, 12:37 PM
Nope... It been doing the double paint thing way before I added the refreshlist addition. I only added the refresh code when that ghost slot bug appeared and that a manual refreshlist command removed it remember. If I could save a log of the output from the console I would be able to show you what's happening but it's another bug in NRD which is slowing down development.

Can we PLEASE have an ability where we can output the console log to a logfile or be able to copy the log like we can do in Girder? I did say that having the code wouldn't really help with not having an Xbox to test on.

If you don't get a double paint I guess that I need to look at the Girder program if it's not a normal occurance. If Info is being updated twice for some reason I suppose it could be the cause of the double paint so at least it's given me somewhere else to look (ie it could be a Girder code problem... that program has been built during the learning process and I'm not too happy with some of it). Like I said, I can't do anything atm because I'm feelling really crappy due to this darn migraine (that still hasn't gone away would you believe). :mad: Once I'm feeling better I'm determined to get to the bottom of this problem as it's the only thing that's not working but other than adding the extra ghost slots it's not stopping the interface from working.

On another point, you did say earlier in the thread you have a solution. Any chance of seeing how you managed to solve it so I know how? Example code would really help (as usual).

Rob H
November 24th, 2007, 02:28 PM
Re the console thing - remember that you can use DebugView from SysInternals to log NetRemote messages; that will allow you to copy lines from the log. I agree though that this should be in NRD.

Sorry to hear about the migraine.

The best example I have is actually in LDJ2, but it is rather mixed in with other code. The code is actually for Girder's version of ListManager, but they're pretty much interchangeable. See luascript\LDJ\UI.lua - the relevant methods are NewContext(), SetContext(), Refresh(), Pop() and SetCurrentFolder().

I hope you can make sense of them as they use a new object system what I wrote :) which forces you to declare all properties and creates the Get and Set methods automatically.

The core of the idea is that when you drill down you create a context table containing everything you want to preserve, e.g. the entries, topMost and selected items and push that onto a stack. When you come back up again you pop the stack and restore the context. I may add something like this to a later version of ListManager if I can wrap up the context in a suitable object.

NeoMorph
November 26th, 2007, 06:54 AM
Turns out the "migraine" wasn't a migraine at all... I have a darned sinus infection. I should have realised when it wasn't going away properly with the migraine meds. :(

When I'm feeling better I'll have a look at your code but if you look at my feeble effort you will know all I have been storing in a stack is the position I am at when I'm drilling down through the directories. All I need is a foolproof way of positioning the list to the correct page when I return back up through the list. Currently I store "LM.topMost" but resetting it to the right page is being thrown by that double paint I'm getting. If the fault's going to be anywhere it's going to be in my girder code I'm thinking. Trying to fix program A for a fault in program B is kind of silly don't you think... at least it will explain why I've had no luck with it (and I've tried all sorts of wierd and wonderful workarounds like that refreshlist hack.)

NeoMorph
November 26th, 2007, 09:30 AM
Rob I was feeling a little better this afternoon so I decided to have a look at the code again. Found some really interesting stuff too.


Info isn't being updated twice so it's not that side of things. So back the to NR program.
I put print statements into the program so I could follow the flow. It seems that the OnPressed function exits and then it refreshes the list, then the table changes and then the list is updated again.
I replaced OnPressed with a completely empty function so when you press the button nothing should happen... wrong... the darn thing refreshes the list when you press the button.. god knows why. I can't see any code that actually generates the refresh and I've chopped the code up so much that I have NO refresh statements now so I haven't a clue where the darn problem is.I really, REALLY need a NR debugger so I can step through the code to find out where the first refresh is being called from because I can't see it and the panel code is being chopped away and it's still doing the damned refresh. It's definately something to do with my code that I think is causing your Listmanager to have a fit or something.

I'll keep at it because it's really annoying not being able to find what's causing it... oh and annoying because there is no darned search or debugger for NR as of yet. Got to say NR is pretty poor for debugging and I'd give it a 3/10 where I would give Girder a 9.5/10 for the debugging side of things. Girder is so much more polished than NRD now.

Do you have any rough idea when the new NRD with debugger is going to be released into the wild because I'm banging my head against a brick wall here and it's hurting enough with the sinus infection as it is?

NeoMorph
November 26th, 2007, 10:06 AM
Well I'm well and truly baffled!

I've chopped and chopped and chopped until the Lua file contains just this...


require "ListManager"
ChannelManager = ListManager:New("xbmc", 14, Info)
ChannelManager.OnPaint = function(ChannelManager, entry, index)
print("--- ".. index .. " ---")
end
function XBMClisting()
print(">>> Info Must Have Changed")
ChannelManager :UpdateEntries(Info)
end
RegisterVariableWatch('Info.changed',XBMClisting);



... and yet still when I press a button in the list it generates an OnPaint. Surely it shouldn't refresh the whole list just because I pressed the button...

Grrr....

I don't know what else to do. I guess it's forget the whole thing until the debugger comes along because I'd really getting frustrated about the whole thing. I suppose I should try and make a new demo that hopefully demonstrates the problem without having to use an Xbox.

God I hate this panel at times... :mad:

Rob H
November 26th, 2007, 02:59 PM
Ah, yes, when you press a button it will repaint the list - the reason is that it will potentially have changed the selected item so the previous selection and the new selection will need to be painted. If the user has implemented their own form of multiple selection then all items may need repainting. See the SelectIndex() method.

NeoMorph
November 27th, 2007, 04:24 AM
Arrggghhh.... *bangs head on table*

So it wasn't my code after all... :p Here is me trying to figure out what I had done wrong for like three hours because you assured me that it doesn't paint twice. Oooh you sooo owe me a pint for that misleading remark... except I don't drink... arrrgggh

So how do I use that SelectIndex statement because it doesn't say how in the help file as usual. It's a bit like a line in a recipe saying "Carrots" without saying how to use them... do I chop them, slice them or use whole! Sameways how do I use the statement with just a syntax line without any explanation as to what it does and how to use it. ;)

Rob H
November 27th, 2007, 04:29 AM
You don't normally directly call SelectIndex - if you're using LMAuto then it will be called automatically.

NeoMorph
November 27th, 2007, 04:38 AM
So.... what is causing this darned ghost slot appearing then! Resetting topMost does work but for that darned empty slot not being hidden... but does subsequently hide if you manually do a refreshlist (which was what I tried to code in as a workaround).

It looks like you may have a bug after all if it's displaying the slot when it shouldn't but then does realise if you manually do the refreshlist.

Rob H
November 27th, 2007, 06:36 AM
Okay, can you add the lines


if entry then
print('Got an entry for index '..i)
else
print('No entry for index '..i)
end

to the start of your OnPaint and try to reproduce the problem.

In theory, it should say 'No entry for index 14' when the slot is empty

NeoMorph
November 28th, 2007, 05:08 PM
Sorry I haven't replied Rob but this sinus infection is really knocking me for six and the anti-biotics for another six :(

I'll have a go when I'm feeling better. Thanks for trying though... much appreciated.