Lua: Select vs Update

Started by garry23, June 02, 2016, 08:49:56 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

garry23

David

You said something yesterday that I understood, but I can't work out. That is the use of the update triggered function call in a menu vs select triggered.

Here is the menu that's confusing me:

{
name = "Enabled?",
help = "Switches the script on/off",
choices = {"Yes","No"},
select = function(this) -- set all Toggler menus to their off state
if this.value == "Yes" then
menu.set("Shoot","Silent Picture",0)
menu.set("Shoot","Advanced Bracket",0)
menu.set("Expo","Auto ETTR",0)
menu.set("Expo","Dual ISO",0)
toggler_play = 1
frsp = false
end
end
}


In the above I used select, and I can not cycle through choices and the menu doesn't change.

If I replace select with update, choices toggles and all looks good.

Can you throw some light on the above?

Cheers

Garry

dmilligan

Ah, if you use select, then you need to change the menu's value yourself manually in the select function.

garry23

I thought it might be something like that  ;)

I'll play around with some ideas.

Cheers

Garry

garry23

Sorry to bother you David...I'm pulling my hair out with this menu call

{
name = "Enabled?",
help = "Switches the script on/off",
choices = {"Yes","No"},
select = function(this) -- set all Toggler menus to their off state
if this.value == "Yes" then
menu.set("Shoot","Silent Picture",0)
menu.set("Shoot","Advanced Bracket",0)
menu.set("Expo","Auto ETTR",0)
menu.set("Expo","Dual ISO",0)
toggler_play = 1
frsp = false
if this.value == "Yes" then keymenu.submenu["Enabled?"].value = "Yes" else keymenu.submenu["Enabled?"].value = "No" end
end
end
}


Whatever I do, the choices options never appear on the menu.

Can you put me out of my misery  :-[

Cheers

Garry

dmilligan


{
    name = "Enabled?",
    help = "Switches the script on/off",
    choices = {"Yes","No"},
    select = function(this)

        --update the menu value
        if this.value == "Yes" then
            this.value = "No"
        else
            this.value = "Yes"
        end

        -- set all Toggler menus to their off state
        if this.value == "Yes" then
            menu.set("Shoot","Silent Picture",0)
            menu.set("Shoot","Advanced Bracket",0)
            menu.set("Expo","Auto ETTR",0)
            menu.set("Expo","Dual ISO",0)
            toggler_play = 1
            frsp = false
        end
    end
}

garry23

David

I tried that approach earlier today and it did not work.

{
name = "Enabled?",
help = "Switches the script on/off",
choices = {"Yes","No"},
select = function(this)
if this.value == "Yes" then
this.value = "No"
else
this.value = "Yes"
end
if this.value == "Yes" then -- set all Toggler menus to their off state
menu.set("Shoot","Silent Picture",0)
menu.set("Shoot","Advanced Bracket",0)
menu.set("Expo","Auto ETTR",0)
menu.set("Expo","Dual ISO",0)
toggler_play = 1
frsp = false
end
end
}


With the above neither the camera toggle or SET button does anything.

All I see in the menu is the menu name: "Enabled?"

dmilligan

Try this:

name = "Enabled",
choices = {"Off","On"},
icon_type = ICON_TYPE.BOOL,
select = function(this)
    if this.value == "Off" then
        this.value = "On"
    else
        this.value = "Off"
    end
end,


or this:

name = "Enabled",
min = 0,
max = 1,
icon_type = ICON_TYPE.BOOL,
select = function(this)
    if this.value == 0 then
        this.value = 1
    else
        this.value = 0
    end
end,

garry23

 :)

The first option works, ie

{
name = "Enabled?",
help = "Switches the script on/off",
choices = {"No","Yes"},
icon_type = ICON_TYPE.BOOL,
select = function(this)
if this.value == "Yes" then
this.value = "No"
else
this.value = "Yes"
end
if this.value == "Yes" then -- set all Toggler menus to their off state
menu.set("Shoot","Silent Picture",0)
menu.set("Shoot","Advanced Bracket",0)
menu.set("Expo","Auto ETTR",0)
menu.set("Expo","Dual ISO",0)
toggler_play = 1
frsp = false
end
end
}


I needed to switch the choices, as the first choice is 'grey out', which works if No is first rather than Yes.

Not sure why it now works...but thanks for your help.

Cheers

Garry

dmilligan

Quote from: garry23 on June 02, 2016, 03:29:33 PM
Not sure why it now works...but thanks for your help.
It works because you need to let the ML menu backend know what type of menu item it is. I guess the auto-detection failed b/c you are using a custom select function and it assumes IT_ACTION. So what made it work was explicitly declaring the type:

icon_type = ICON_TYPE.BOOL


Then you have to switch the "No" option first because that is an ML convention (and because in C, 0 means false). I would also recommend dropping the "?" in the name and using "Off"/"On" for consistency with other ML menus.

garry23

David

Got it: thanks.

One question: what if the choices was, say, three-way, instead of 'binary':
choices = {"No","Yes","Maybe"}

I guess the following wont work then?

icon_type = ICON_TYPE.BOOL

Also, I originally had OFF/ON but changed that as the LV Toggler feedback uses OFF, when in fact Toggler is ON !

Cheers

Garry

dmilligan

Yes, it would still work. "No" would show up greyed out, and "Yes" and "Maybe" would show up as green and enabled (in C, 0 = false, nonzero = true)

garry23

Great to know  ;)

C seems a bit like some of those Amazon tribes whose counting system is along the lines of 0, 1, 2, many  :)

Cheers

Garry

dmilligan

Its actually like that because of the way CPUs work. Typical CPU architectures have a status register that includes a Z (zero) flag, that says whether or not the result of the previous operation was zero, and there are typically conditional branching operations that either branch or don't branch based on the Z flag.

So for example this C code:

if(a == b)
{
    //do something
}
//continue


Turns into relatively simple (pseudo) assembly:

    LDR  r1 a       ; load register 1 with a
    LDR  r2 b       ; load register 2 with b
    SUBS r1,r1,r2   ; r1 = r1 - r2
    BEQ  label      ; branch if Z flag set
    ;do something
label:
    ;continue

garry23

David

Thanks for the continuing education. I really appreciate it.

Unfortunately I continue to have 'problems' as I attempt to follow your guidance.

Here is a sample piece of problematic code:

{
name = "LE mode?",
rinfo = function(this)
if keymenu.submenu["LE mode?"].submenu["select"].value == 0
then return "off"
else return "active"
end
end,
help = "In seconds or frames. Zero = no LE bracketing",
halp2 = "LE or frame bracketing trumps all other bracketing modes",
           submenu =
            {
                {
name = "select",
min = 0,
max = 120,
icon_type = ICON_TYPE.AUTO,
select = function(this, delta)
this.value = this.value + delta
if this.value > this.max then
this.value = this.min
elseif this.value < this.min then
this.value = this.max
end
if keymenu.submenu["LE mode?"].submenu["select"].value > 0 then
menu.set("Auto Bracketing","Ev bracket delta per image",0)
menu.set("Auto Bracketing","Focus bracketing?","no")
end
end,
rinfo = function(this)
if keymenu.submenu["LE mode?"].submenu["Mode?"].value == "time" then return "secs" else return "frames" end
end,
warning = function(this)
if keymenu.submenu["LE mode?"].submenu["Mode?"].value == "time" then
LE_brackets = math.ceil(keymenu.submenu["LE mode?"].submenu["select"].value/camera.shutter.value)
if LE_brackets == 0 then
return "LE bracket taking switched off"
else
return "Note: "..tostring(LE_brackets).." brackets will be taken"
end
end
end
                },
                {
name = "Mode?",
choices = {"time","# frames"},
help = "In seconds or #frames. Zero = no LE bracketing",
                }
            }
        },


When I go into the submenu (select) I can change things OK, the problem is the 'Q' doesn't work and if I press this, to return to the parent menu, the menu freezes.

I've tried various changes to the code, but no luck.

Can your 'magic eye' spot the errors of my ways?

Cheers

Garry

garry23

David

In further testing, where I have reduced the menu code to this:

{
name = "LE mode?",
rinfo = function()
if keymenu.submenu["LE mode?"].submenu["choose"].value == 0
then return "off"
else return "active"
end
end,
help = "In seconds or frames. Zero = no LE bracketing",
halp2 = "LE or frame bracketing trumps all other bracketing modes",
           submenu =
            {
                {
name = "choose",
min = 0,
max = 120,
icon_type = ICON_TYPE.BOOL,
select = function(this, delta)
this.value = this.value + delta
if this.value > this.max then
this.value = this.min
elseif this.value < this.min then
this.value = this.max
end
end,
                },
                {
name = "Mode?",
choices = {"time","# frames"},
help = "In seconds or #frames. Zero = no LE bracketing",
                }
            }
        },


I see that if I choose a zero value, even if I have moved away from this to other values frist, Q works, ie returns the submenue to the parent. If I choose a non-zero value Q freezes.

I'm stumped as the problem is only in this submenu.

I hope you have some ideas?

Cheers

Garry

garry23

David

I spent today investigating, by going back to the last stable version and adding code until the Q button freeze problem. It seemed to occur when I used select, update and warning together. I surmise my code was becoming a burden for the 'cpu'.

Any way I rewrote things and all looks stable now:

--[[
Auto Bracketing Script
Auto focus bracketing with exposure bracketing
Plus the script does both time and frame bracketing, ie for LE situations
Release 1.0
This version has some error detection, but the user must be aware of certain things:
* Check the correct DoF diffraction options are set in ML, eg diffraction aware is on for best data
* Must use a lens that reports focus distance and DoF can be calculated
* Lens must be in AF mode
* Must be in manual mode
* Switch stabalisation off as you will not be hand holding ;-)
* Must be in LV mode: script won't run unless in LV
* ETTR ON: settings recommended are - no link to dual, SNRs to OFF, highlights very low or zero (your choice_, and not Always On or Auto Snap
* as this may 'confuse' the script
* You can switch focus bracketing on/off in the menu, ie use LE and/or exposure mode alone. The script handles the logic, ie if LE mode is being used,
* then you can't use focus or exposure bracketing
* Image review must not be set to HOLD in Canon menu
* Assumes lens is focused at nearest point to start a focus stack, ie script moves to infinity
* Script takes last bracket with focus point at infinity
* When exposure bracketing, set base exposure to capture shadows (the script will calculate the ETTR of the scene)
* If ETTR fails, then try adjusting ETTR set time to give your camera more time (or experiment with less)
* Final thought: photography should be relaxing, hence I personally don't mind that this script takes time to run. As it's
* running, look around you and enjoy nature and the moment :-)
*******************************************************************************************************
*   *
* If you reference this script, please consider acknowledging me at http://photography.grayheron.net/ *
*   *
*******************************************************************************************************
--]]

-- Declare a few variables for the script whick load when camera switced on
a1 = 0
b1 = 0
a2 = 0
b2 = 0
fp = 0
inf = 100000
base_tv = 0
delay = 0
factor = 0
num_brackets = 0
ETTR_tv = 0
base_tv = 0
user_tv = 0
LE_brackets = 0
running = false
no_tv_error = true
brackets_requested = false

function reset()  -- tidy up at the end
no_tv_error = true
brackets_requested = false
running = true
display.notify_box("***FINISHED***",4000)
beep (3, 200 , 1000)  -- notify end of script
display.clear()
end

function my_shoot()
if camera.shutter.apex < -4 then
camera.bulb(camera.shutter.value)
else
camera.shoot(64, false)
end
end

function check_bookend()
if keymenu.submenu["Bookends?"].value == "yes"
then
local tv = camera.shutter.ms
local av = camera.aperture.value
camera.shutter.ms = 1
camera.aperture.apex = 9
my_shoot()
camera.shutter.ms = tv
camera.aperture.value = av
end
end

function find_ETTR()
-- Find the ETTR shutter value: make sure you have set ML ETTR values correctly
local m = menu.get("Auto ETTR","Trigger mode")
menu.set("Auto ETTR","Trigger mode",0) -- set ETTR menu to get an ETTR exposure
local check_tv = 0
repeat -- hang around until ETTR value has stabilised
check_tv = camera.shutter.apex
msleep (keymenu.submenu["ETTR Set Time?"].value*1000)  -- adjust this for your camera. The time delay allows the ML ETTR process to settle down
until check_tv == camera.shutter.apex
ETTR_tv = camera.shutter.apex
menu.set("Auto ETTR","Trigger mode",m) -- reset to user ETTR menu setting
if ETTR_tv < base_tv
then -- base TV needs resetting
display.notify_box("Warning Shadow Tv < ETTR Tv",4000)
beep (3, 200 , 500)  -- warning message
no_tv_error = false
end
end

function calc_brackets()
if no_tv_error then
num_brackets = (ETTR_tv - base_tv)/factor
num_brackets = math.floor(math.abs(num_brackets))
if num_brackets <= 1 then num_brackets = 1 end
end
end

function check_LE()
-- Check to see if user has requested LE bracketing of some kind
if keymenu.submenu["LE mode?"].submenu["select"].value ~= 0
then
if keymenu.submenu["LE mode?"].submenu["Mode?"].value == "time"
then
LE_brackets = math.ceil(keymenu.submenu["LE mode?"].submenu["select"].value/camera.shutter.value)
else
LE_brackets = keymenu.submenu["LE mode?"].submenu["select"].value
end
brackets_requested = true
end
end

function take_brackets()
local i
if LE_brackets == 0
then
if no_tv_error and brackets_requested then -- take exposure brackets
camera.shutter.apex = ETTR_tv
my_shoot()
for i = 1, num_brackets , 1
do
camera.shutter.apex = camera.shutter.apex - factor
my_shoot()
end
if camera.shutter.apex > base_tv
then
camera.shutter.apex = base_tv
my_shoot()
end
else -- take a single image
camera.shutter.apex = base_tv
my_shoot()
end
else -- take some LE bracketing images
for i = 1, LE_brackets , 1
do
my_shoot()
end
end
end

function albs()
if brackets_requested and keymenu.submenu["LE mode?"].submenu["select"].value == 0 then
find_ETTR()
calc_brackets() -- number of exposure brackets
else
msleep(keymenu.submenu["Script delay"].value*1000)  -- delay in ms
end
if no_tv_error then check_bookend() end
-- Get DoF info & take first(only) exposure(s)
a2 = lens.dof_near
b2 = lens.dof_far
if no_tv_error then take_brackets() end
-- Take focus brackets to infinity if requested
if keymenu.submenu["Focus bracketing?"].value == "yes"
then -- do focus bracketing
if lens.focus_distance < inf and no_tv_error then
repeat
a1=a2
b1=b2
repeat
lens.focus(-1,1)
b2 = lens.dof_far
a2 = lens.dof_near
fp = lens.focus_distance
until a2 > b1 or fp >= inf
lens.focus(1,1) -- move back one step for focus bracket overlap
take_brackets()
until fp >= inf
end
end
if no_tv_error then check_bookend() end
reset()  -- do some tiding up beforing exiting
end

function setup() -- does some checking before calling the main function
menu.close()
factor = tonumber(keymenu.submenu["Ev bracket delta per image"].value) -- set exposure bracketing offset (0, 1 or 2)
if not lv.enabled then lv.start() end -- just in case
if camera.model_short == "EOSM" then
display.notify_box("Sorry doesn't work with the EOSM", 3000)
else
check_LE()
if factor ~= 0 then brackets_requested = true else brackets_requested = false end
if running -- then script has already been used since camera switched on
then -- reset some stuff...just to be sure :-)
no_tv_error = true
end
if lens.focus_distance ~= 0 and lens.af -- lens is OK
then -- fit to run the main function
base_tv = camera.shutter.apex
albs() 
else  -- lens not OK!
beep (3, 200 , 500)  -- warning message
display.notify_box("Check your lens", 5000)
end
end
end

keymenu = menu.new
{
    parent = "Shoot", -- change this to position the script into other ML menu locations
    name = "Auto Bracketing",
    help = "Remember: set LV, DoF & AF on",
depends_on = DEPENDS_ON.LIVEVIEW,
warning = function(this)
if menu.get("Expo","Auto ETTR") == 0 then return "ETTR switched off" end
end,
    submenu =
{
{
name = "Run Script",
help = "Does what it says after pressing SET",
warning = function(this)
if not lv.enabled then return "LV not enabled" end
if menu.get("Expo","Auto ETTR") == 0 then return "ETTR switched off" end
end,
select = function(this)
if menu.get("Expo","Auto ETTR") ~= 0 and lv.enabled and key.last == KEY.SET then task.create(setup) end
end
},
{
name = "Focus bracketing?",
help = "Switches focus bracketing mode on/off",
choices = {"no","yes"},
icon_type = ICON_TYPE.BOOL,
warning = function(this)
if keymenu.submenu["LE mode?"].submenu["select"].value ~= 0 then
menu.set("Auto Bracketing","Focus bracketing?",0)
return "LE mode on"
end
end
},
{
name = "Ev bracket delta per image",
help = "0 = no auto exposure bracketing",
min = 0,
max = 2,
icon_type = ICON_TYPE.BOOL,
warning = function(this)
if keymenu.submenu["LE mode?"].submenu["select"].value ~= 0 then
menu.set("Auto Bracketing","Ev bracket delta per image",0)
return "LE mode on"
end
end
},
{
name = "LE mode?",
rinfo = function(this)
if keymenu.submenu["LE mode?"].submenu["select"].value == 0
then return "off"
else return "active"
end
end,
help = "In seconds or frames. Zero = no LE bracketing",
help2 = "LE or frame bracketing trumps all other bracketing modes",
      submenu =
            {
      {
name = "select",
min = 0,
max = 300,
icon_type = ICON_TYPE.BOOL,
rinfo = function(this)
if keymenu.submenu["LE mode?"].submenu["Mode?"].value == "time" then return "secs" else return "frames" end
end,
select = function(this,delta)
this.value = this.value + delta
if this.value > this.max then
this.value = this.min
elseif this.value < this.min then
this.value = this.max
end
if this.value ~= 0 then
menu.set("Auto Bracketing","Ev bracket delta per image",0)
menu.set("Auto Bracketing","Focus bracketing?",0)
end
end,
warning = function(this)
if keymenu.submenu["LE mode?"].submenu["Mode?"].value == "time" then
LE_brackets = math.ceil(keymenu.submenu["LE mode?"].submenu["select"].value/camera.shutter.value)
if LE_brackets == 0 then
return "LE bracket taking switched off"
else
return "Note: "..tostring(LE_brackets).." brackets will be taken"
end
end
end
              },
        {
name = "Mode?",
choices = {"time","# frames"},
help = "In seconds or #frames. Zero = no LE bracketing",
              }
        }
},
{
name = "Bookends?",
help = "Places a dark frame at start and end of focus bracket set",
choices = {"no","yes"},
icon_type = ICON_TYPE.BOOL,
},
{
name = "Script delay",
help = "Delays script start by stated number of secs",
min = 0,
max = 5,
icon_type = ICON_TYPE.BOOL,
select = function(this,delta)
if this.value == 0 then
this.value = 2
elseif this.value == 2 then
this.value = 5
elseif this.value == 5 then
this.value = 0
end
end
},
{
name = "ETTR Set Time?",
help = "A camera specific variable in seconds",
help2 = "Change if ETTR fails to find a solution",
min = 2,
max = 8,
value = 4
}
}
}


I also have created a gist: https://gist.github.com/pigeonhill/750536059c927edaa55b34a6236ae8e1

I still see some 'weird' stuff, ie the two submenus under the LE menu are always greyed out, but function fine. Also the main menu reference is grey and I don't understand that either.

Cheers

Garry

garry23

 :)

Worked out the grey menus, ie created by warning if you return a "".

:)