Page 1 of 2

Screen manager.

Unread postPosted: 01 Aug 2014, 07:48
by NspireCas
Bonjour,

Je ne comprends pas comment utiliser le screen manager du tutoriel d'inspired lua :

Show/Hide spoilerAfficher/Masquer le spoiler
Code: Select all
------ Screen Manager
Screen = class()

function Screen:init() end

-- virtual functions to override
function Screen:paint(gc) end
function Screen:timer() end
function Screen:charIn(ch) end
function Screen:arrowKey(key) end
function Screen:escapeKey() end
function Screen:enterKey() end
function Screen:tabKey() end
function Screen:contextMenu() end
function Screen:backtabKey() end
function Screen:backspaceKey() end
function Screen:clearKey() end
function Screen:mouseMove(x, y) end
function Screen:mouseDown(x, y) end
function Screen:mouseUp() end
function Screen:rightMouseDown(x, y) end
function Screen:help() end

local Screens = {}

function PushScreen(screen)
    table.insert(Screens, screen)
    platform.window:invalidate()
end

function PullScreen()
    if #Screens > 0 then
        table.remove(Screens)
        platform.window:invalidate()
    end
end

function activeScreen()
    return Screens[#Screens] and Screens[#Screens] or Screen
end

-- Link events to ScreenManager
function on.paint(gc)
   for _, screen in pairs(Screens) do
        screen:paint(gc)
    end
end

function on.timer()
    for _, screen in pairs(Screens) do
        screen:timer()
    end
end

function on.charIn(ch) activeScreen():charIn(ch) end
function on.arrowKey(key) activeScreen():arrowKey(key) end
function on.escapeKey()   activeScreen():escapeKey() end
function on.enterKey() activeScreen():enterKey() end
function on.tabKey() activeScreen():tabKey() end
function on.contextMenu() activeScreen():contextMenu() end
function on.backtabKey() activeScreen():backtabKey() end
function on.backspaceKey() activeScreen():backspaceKey() end
function on.clearKey() activeScreen():clearKey() end
function on.mouseDown(x, y) activeScreen():mouseDown(x, y) end
function on.mouseUp() activeScreen():mouseUp() end
function on.mouseMove(x, y) activeScreen():mouseMove(x, y) end
function on.rightMouseDown(x, y) activeScreen():rightMouseDown(x, y) end
function on.help() activeScreen():help() end

function on.create() PushScreen(Menu()) end
function on.resize() end


J'aurais besoin d'un gestionnaire d'environ une quarantaine d'écrans, mais j'apprécierai si on me montrait comment au moins gérer deux écrans (où un texte sera affiché par exemple).

Merci d'avance . :)


Edit : Je vous joins le genre de programmes que je veux faire, une sorte de menu où on se déplace avec les 4 flèches directionnelles (pour l'instant il y a 3 screens, le troisième dans la catégorie 'loi normale').
Le code va être de plus en plus long si j'augmente le nombre d'écrans, aussi avec un screen manager je pourrais éviter d'utiliser de multiples compteurs qui me servent d'une part à savoir le nombre d'écrans où je suis passé depuis le début, et d'une autre part à connaître la position de la flèche noire dans le menu.

Re: Screen manager.

Unread postPosted: 01 Aug 2014, 11:30
by Adriweb
Je ne sais pas trop ce que tu ne comprends pas dans le code que tu as posté (attention au PushScreen qui est dans le on.create, cependant...), mais il y a eu une nouvelle façon de faire, depuis, moins lourde :

http://inspired-lua.org/index.php/2013/ ... r/?lang=fr

2 exemples sont disponibles à la fin (un simple pour le tutorial, et un montrant le code utilisé dans un jeu)

Re: Screen manager.

Unread postPosted: 01 Aug 2014, 12:01
by NspireCas
Est-ce vraiment la meilleure solution si je veux une sorte de menu avec une flèche noire qui indique le choix ?

ça m'a l'air compliqué ... Vous avez fait un screenManager pour éviter les longs codes pleins de 'if' mais je ne comprends pas comment cela est évité ...

Regardez ce code par exemple : (je ne pense même pas que le screen manager puisse m'aider dans ce genre de truc...)

Show/Hide spoilerAfficher/Masquer le spoiler
Code: Select all
screen = platform.window

function on.construction()
  compteur = 0
  abscisse=35
  fleche=15
  compt=1
  compt2=1
end

function on.paint(gc)
  if compteur == 0 then
     gc:setFont("serif", "bi", 24)
     gc:setColorRGB(255, 0, 0)
     gc:drawString("Probabilités", 80, 80)
  elseif compteur == 1 then
     gc:setFont("serif", "b", 16)
     gc:drawString("▶",15,40*compt-10)
     gc:drawString("Loi Normale.", 35, 30)
     gc:drawString("Loi Exponentielle.", abscisse, 70)
     gc:drawString("Loi Uniforme.", abscisse, 110)
     gc:drawString("Loi à Densité.", abscisse, 150)
  elseif compteur == 2 then
    if compt == 1 then
       gc:setFont("serif", "b", 16)
       gc:drawString("▶",15,40*compt2-10)
       gc:drawString("Calcul d'une probabilité.", 35, 30)
       gc:drawString("Recherche d'un réel tel que ...", abscisse, 70)
       gc:drawString("Recherche de l'écart-type.", abscisse, 110)
       gc:drawString("Recherche de l'espérance.", abscisse, 150)
    elseif compt == 2 then
    elseif compt == 3 then
    elseif compt == 4 then
    end
  end
end

function on.enterKey()
  if compteur < 2 then
    compteur = compteur+1
  end
  screen:invalidate()
end

function on.escapeKey()
  if compteur > 0 then
    compteur = compteur-1
  end
  screen:invalidate()
end
function on.arrowUp()
  if compt~=1 and compteur == 1 then
    compt = compt-1
  end
  if compt2~=1 then
    compt2 = compt2-1
  end
  screen:invalidate()
end

function on.arrowDown()
  if compt2~=4 then
    compt2 = compt2+1
  end
  if compt~=4 and compteur == 1 then
    compt = compt+1
  end
  screen:invalidate()
end


Merci de ta réponse Adriweb.

Re: Screen manager.

Unread postPosted: 01 Aug 2014, 12:26
by Adriweb
Justement, les screen managers sont spécialement fait pour éviter ce genre de situations avec plein de if :P
Tu crées autant de screen que de parties qu'il y aura dans ton programme, et a travers les choix que tu fais dans les menus, tu push le screen voulu.
Et avec ESC (par exemple), tu le retires.


Pour le menu que tu veux faire, tu peux utiliser le bout de code que Jim a fait dans son jeu de memory (c'est le deuxième lien d'exemple de l'article d'Inspired-Lua que j'ai linké, justement).
C'est plutôt simple :
Code: Select all
do
    Menu = Screen()
   
    local menuEntries = {"New Game", "Load Game", "Save Game", "About"}
    local posShow = 20
   
    local cStep = #menuEntries
    local pos = posShow
    local selected = 1
           
    function Menu:paint(gc)
        local width, height = platform.window:width(), platform.window:height()
       
        gc:setColorRGB(100, 120, 200)
        gc:fillRect(0, 0, width, height) 
       
        gc:setFont("sansserif", "r", 12)
       
        local style
        for i=1, cStep do
            gc:setColorRGB(255, 255, 255)
            style = "r"
                       
            if i == selected then
                style = "b"
                gc:drawString(string.uchar(0x25B6), posShow - 10, i * 30 - 15, "top")
            end
         
            gc:setFont("sansserif", style, 12)
            gc:drawString(menuEntries[i], posShow, i * 30 - 15, "top")
        end
       
        gc:setFont("sansserif", "r", 9)
        local p = 5 * 30 - 15
       
        if selected == 4 then
            local c = string.uchar(0x25AA)
            gc:drawString(c.."  Made by Jim Bauwens", posShow, p, "top")
            gc:drawString(c.."  For TI-Concours 2013", posShow, p+13, "top")
            gc:drawString(c.."  No shrimps were harmed", posShow, p+26, "top")
            gc:drawString("   while making this game", posShow, p+39, "top")
        end
    end
   
    function Menu:arrowUp()
        if selected > 1 then
            selected = selected - 1
        end
        platform.window:invalidate()
    end
   
    function Menu:arrowDown()
        if selected < #menuEntries then
            selected = selected + 1
        end
        platform.window:invalidate()
    end
   
    function Menu:enterKey()   
        if selected == 1 then
            Main:newGame()
            PushScreen(Main)
        elseif selected == 2 and savedGame then
            Main:loadSaveGame(savedGame)
            PushScreen(Main)
        elseif selected == 3 and Main.gameRunning and not Main.finished then
            savedGame = Main:getSaveGame()
            document.markChanged()
        end   
       
        platform.window:invalidate()
    end
end

Re: Screen manager.

Unread postPosted: 01 Aug 2014, 12:32
by NspireCas
ok, je vais voir et je te tiens au courant.

Par contre sur ton bout de code j'ai rajouté Screen = class() au début du code, l'erreur du Screen=nil value part mais le programme n'affiche rien :0.

Re: Screen manager.

Unread postPosted: 01 Aug 2014, 12:37
by Adriweb
Ah oui, c'est normal, il te faut adapter le code du Menu selon tes besoins, et surtout, avoir le code du screen manager...

Au final, ça donne ça :

Code: Select all
local screens = {}
local screenLocation = {}
local currentScreen = 0

function RemoveScreen(screen)
    screen:removed()
    table.remove(screens, screenLocation[screen])
    screenLocation[screen] = nil
    currentScreen = #screens -- sets the current screen as the top one on the stack.
    if #screens<=0 then print("Uh oh. This shouldn't have happened ! You must have removed too many screens.") end
end

function PushScreen(screen)
    -- if already activated, remove it first (so that it will be on front later)
    if screenLocation[screen] then
        RemoveScreen(screen)
    end

    table.insert(screens, screen)
    screenLocation[screen] = #screens

    currentScreen = #screens
    screen:pushed()
end

function GetScreen()
    return screens[currentScreen] or RootScreen
end

Screen = class()

function Screen:init() end

function Screen:pushed() end
function Screen:removed() end

RootScreen = Screen() -- "fake", empty placeholder screen.

local eventCatcher = {}
local triggeredEvent = "paint"

local eventDistributer = function (...)
     local currentScreen = GetScreen()
     if currentScreen[triggeredEvent] then
         currentScreen[triggeredEvent](currentScreen, ...)
     end
end

eventCatcher.__index = function (tbl, event)
    triggeredEvent = event
    return eventDistributer
end

-- finally linking everything
setmetatable(on, eventCatcher)


do
    Menu = Screen()
   
    local menuEntries = {"New Game", "Load Game", "Save Game", "About"}
    local posShow = 20
   
    local cStep = #menuEntries
    local pos = posShow
    local selected = 1
           
    function Menu:paint(gc)
        local width, height = platform.window:width(), platform.window:height()
       
        gc:setColorRGB(100, 120, 200)
        gc:fillRect(0, 0, width, height) 
       
        gc:setFont("sansserif", "r", 12)
       
        local style
        for i=1, cStep do
            gc:setColorRGB(255, 255, 255)
            style = "r"
                       
            if i == selected then
                style = "b"
                gc:drawString(string.uchar(0x25B6), posShow - 10, i * 30 - 15, "top")
            end
         
            gc:setFont("sansserif", style, 12)
            gc:drawString(menuEntries[i], posShow, i * 30 - 15, "top")
        end
       
        gc:setFont("sansserif", "r", 9)
        local p = 5 * 30 - 15
       
        if selected == 4 then
            local c = string.uchar(0x25AA)
            gc:drawString(c.."  Made by Jim Bauwens", posShow, p, "top")
            gc:drawString(c.."  For TI-Concours 2013", posShow, p+13, "top")
            gc:drawString(c.."  No shrimps were harmed", posShow, p+26, "top")
            gc:drawString("   while making this game", posShow, p+39, "top")
        end
    end
   
    function Menu:arrowUp()
        if selected > 1 then
            selected = selected - 1
        end
        platform.window:invalidate()
    end
   
    function Menu:arrowDown()
        if selected < #menuEntries then
            selected = selected + 1
        end
        platform.window:invalidate()
    end
   
    function Menu:enterKey()   
        -- PushScreen(blablabla) -- en fonction de 'selected'
        print(selected)
        platform.window:invalidate()
    end
end

PushScreen(Menu)


(PS : j'ai édité le début de mon post précédent)

PS2 : pour ce genre de trucs (interface multi-levels au niveau des choix), c'est globalement le fonctionnement de FormulaPro :
Image
Comme tu peux le voir, ya un menu, un sous-menu, et le screen "final".
Tu peux t'inspirer de son code, si tu veux. (mais attention, c'est carrément plus lourd :P)

Re: Screen manager.

Unread postPosted: 01 Aug 2014, 17:02
by davidElmaleh
En gros, tu veux faire un menu, comme dans notre programme SuperEspace ?

Pour ma part, j'ai utilisé la méthode la plus débile et la plus facile (mais surtout la plus longue), celle que tu as utilisée au départ. Et franchement, si tu t'organises bien dès le début, ça peut devenir super simple.

Re: Screen manager.

Unread postPosted: 01 Aug 2014, 18:02
by NspireCas
Ouais au début je voulais faire un truc comme ça, et après Adriweb m'a fait pensé à FormulaPro, ça peut être très bien !
Je devrais finir lundi ou mardi.

Re: Screen manager.

Unread postPosted: 03 Aug 2014, 15:33
by NspireCas
Bon pour l'éditeur en ligne de FormulaPro, il faut vraiment prévenir l'utilisateur de locker les variables fonctions et programmes qu'il compte utiliser s'il ne veut pas qu'ils soient supprimés... (Oui je me suis fait avoir :'( :'( :'( )

Re: Screen manager.

Unread postPosted: 03 Aug 2014, 21:53
by Adriweb
Ah, mais... ça génère un .tns donc un document en lui-même, ce n'est pas fait pour être inclus sans faire attention, c'est sûr...
Le fait d'utiliser les variables est voulu, justement pour que les valeurs entrées soient directement utilisables dans les applis de la Nspire, c'est pratique pour faire des graphes etc. en fonction des données, par exemple.

Par ailleurs, tu ne vas quand même as me dire que tu n'as pas de sauvegardes de tes variables (enfin, d'un .tns contenant ce que tu veux) ? ;)