Author Topic: Toggler: Update  (Read 3871 times)

garry23

  • Contributor
  • Hero Member
  • *****
  • Posts: 1807
Toggler: Update
« on: May 31, 2016, 06:45:15 PM »
Like many ML photographers users, I need to switch between various ML settings, eg ETTR on/off, Dual-ISO on/off, FRSP on/off, Auto bracketing on/off.

For me the following script works.

All it does is toggle between the various settings that are important for me, ie those above.

The script is simple and easily extendable.

To use all you need to do is switch it on and toggle: in LV. The toggled state shows up in the top-right of the ML LV bar.

I have programmed the RATE button as my 'toggler': but this can be changed to another button, ie one you don't use a lot. In the case of my EOSM it uses the KEY.UP. The script detects the EOSM.

In the case of the FRSP, the toggler will check you are in the FRSP permissible range.

One final thing, make sure your ML settings are set to your needs, ie the Toggler simply switches the ML function on and off. For example: I use SET for ETTR and put SNRs and link to Dual to off; I set Dual-ISO to 100/800; enable Auto bracketing and use DNG capture in FRSP. But you choose what works for you.

As usual I welcome feedback.

Cheers

Garry

Code: [Select]
--[[
Still photography toggler script
Version 1.1 (should work on all ML enabled cameras with the Lua module)
Garry George May 2016
http://photography.grayheron.net/
Toggler script for ML settings.
Toggle through ML settings using the selected option ie a button you rarely use.
Must be in LV.
--]]

-- Declare some variables
play = 0
toggler = 0

-- Change toggler value to your choice of button, eg KEY.RATE, KEY.UP, KEY.INFO or KEY.PLAY.
-- See http://davidmilligan.github.io/ml-lua/modules/constants.html for key constants
-- Default is KEY.RATE for non-EOSM cameras. EOSM self selects upper toggle on main dial as the EOSM doesn't have many buttons!
if camera.model_short == "EOSM" then toggler = KEY.UP else toggler = KEY.RATE end -- Change RATE to your choice

event.keypress = function(key)
if keymenu.submenu["Turn On/Off"].value == "Off" then
return true -- Toggler does nothing
elseif key == toggler  -- user asking for a 'toggle'
then
play = play + 1
if play == 5 then play = 0 end
return false
end
end

lv.info
{
    name = "Info 1",
    priority = 100,
    value = "",
    update = function(this)
    if keymenu.submenu["Turn On/Off"].value == "On" then
this.foreground = COLOR.YELLOW
this.background = COLOR.BLUE
if play == 0 then
this.value = " Off"
menu.set("Shoot","Advanced Bracket",0)
menu.set("Expo","Auto ETTR",0)
menu.set("Expo","Dual ISO",0)
menu.set("Shoot","Silent Picture",0)
elseif play == 1 then
this.value = "ETTR"
menu.set("Shoot","Advanced Bracket",0)
menu.set("Expo","Auto ETTR",1)
menu.set("Expo","Dual ISO",0)
menu.set("Shoot","Silent Picture",0)
elseif play == 2 then
this.value = "Dual" 
menu.set("Shoot","Advanced Bracket",0)
menu.set("Expo","Auto ETTR",0)
menu.set("Expo","Dual ISO",1)
menu.set("Shoot","Silent Picture",0)
elseif play == 3 then
this.value = "Auto Bracket"
menu.set("Shoot","Advanced Bracket",1)
menu.set("Expo","Auto ETTR",0)
menu.set("Expo","Dual ISO",0)
menu.set("Shoot","Silent Picture",0)
elseif play == 4 then
this.value = "FRSP"
menu.set("Shoot","Advanced Bracket",0)
menu.set("Expo","Auto ETTR",0)
menu.set("Expo","Dual ISO",0)
if camera.shutter.value < 0.2 or camera.shutter.value > 14 then
this.foreground = COLOR.RED
menu.set("Shoot","Silent Picture",0)
else
this.foreground = COLOR.YELLOW
menu.set("Shoot","Silent Picture",1)
end
else
this.value = ""
end
else
this.value = ""
end
end
}

keymenu = menu.new
{
parent = "Shoot",
name = "Toggler",
help = "Toggle through various ML options",
depends_on = DEPENDS_ON.LIVEVIEW,
submenu =
{
{
name = "Turn On/Off",
help = "Switches the script on/off",
choices = {"On","Off"},
}
}
}

dmilligan

  • Developer
  • Hero Member
  • *****
  • Posts: 3218
  • 60Da / 1100D / EOSM
Re: Toggler: Update
« Reply #1 on: June 01, 2016, 03:09:32 AM »
Some suggestions:

- Don't update the menu entries (menu.set) from the lv.info update callback, do it from the key handler. The update callback gets called over and over again, so you're adding an unnecessary (an probably somewhat large) burden on the CPU, you only need to update the menus when the value change. Callbacks like lv.info update and menu update/info/rinfo/warning should be simple and do as little work as possible.

- You can put the presets into tables and greatly simplify your code (and also make it easier to have more or fewer of them without rewriting code).
Code: [Select]
presets =
{
    {
        name = "Off",
        menus=
        {
            { menu = "Shoot", item = "Advanced Bracket", value = 0},
            { menu = "Expo", item = "Auto ETTR", value = 0},
            { menu = "Expo", item = "Dual ISO", value = 0},
            { menu = "Shoot", item = "Silent Picture", value = 0},
        }
    },
    {
        name = "ETTR",
        menus=
        {
            { menu = "Shoot", item = "Advanced Bracket", value = 0},
            { menu = "Expo", item = "Auto ETTR", value = 1},
            { menu = "Expo", item = "Dual ISO", value = 0},
            { menu = "Shoot", item = "Silent Picture", value = 0},
        }
    },

-- and so forth

}

Code: [Select]
play = 1
-- ...

event.keypress = function(key)
    if keymenu.submenu["Turn On/Off"].value == "Off" then
        return true
    elseif key == toggler  then
        play = play + 1
        if play > #presets then play = 1 end
        for i,v in ipairs(presets[play].menus) do
            menu.set(v.menu,v.item,v.value)
        end
        return false
    end
end

lv.info
{
    -- ...
    update = function(this)
        if keymenu.submenu["Turn On/Off"].value == "On" then
            this.foreground = COLOR.YELLOW
            this.background = COLOR.BLUE
            this.value = presets[play].name
        end
    end
}

- It would be nice if you made a way to 'capture' presets. If you use the table scheme above, you can save and load the captured presets using config.

Code: [Select]
require('config')

toggler_config = config.create(presets)
presets = toggler_config:load()

--at some later time whenever presets are 'captured' or modified:
toggler_config.data = presets
toggler_config:save()

garry23

  • Contributor
  • Hero Member
  • *****
  • Posts: 1807
Re: Toggler: Update
« Reply #2 on: June 01, 2016, 08:03:17 AM »
David

First of all many thanks for your continuing mentorship/education.

I think you know I believe Lua is a fantastic addition to ML and allows us to really make our cameras do some impressive (in-camera) stuff, eg my bracketing script for focus, exposure, LE bracketing.

I had seen others/you use ipairs, but bluntly had not understood the ipairs feature in Lua. With the help of your words above, and looking on line, I now think I get it!

I will rewrite Toggler with ipairs; and your guidance.

Once again, many, many thanks  :)

Cheers

Garry

garry23

  • Contributor
  • Hero Member
  • *****
  • Posts: 1807
Re: Toggler: Update
« Reply #3 on: June 01, 2016, 09:44:01 AM »
David

Once again...many thanks.

It only took me a short period to recode using your hints.

I tidied things up, but had to continue to use lv.info to dynamically check the FRSP shutter.

I also exploited the sequential nature of Toggler, ie I only need to set menu items that previously changed.

Once again, thanks for all your support.

Here is the 'refactored' code  :)

Code: [Select]
--[[
Still photography toggler script
Version 1.5 (should work on all ML enabled cameras with the Lua module)
Garry George June 2016
http://photography.grayheron.net/
Toggler script for ML settings.
Toggle through ML settings using the selected option, ie a button you rarely use.
Must be in LV.
--]]

-- Declare some variables
toggler_play = 1
toggler = 0

-- Change toggler value to your choice of button, eg KEY.RATE, KEY.UP, KEY.INFO or KEY.PLAY.
-- See http://davidmilligan.github.io/ml-lua/modules/constants.html for key constants
-- Default is KEY.RATE for non-EOSM cameras. EOSM self selects upper toggle on main dial as the EOSM doesn't have many buttons!
if camera.model_short == "EOSM" then toggler = KEY.UP else toggler = KEY.RATE end -- Change RATE to your choice

toggler_presets =
{
    {
        name = "OFF ",
        menus=
        {
            { menu = "Shoot", item = "Advanced Bracket", value = 0},
            { menu = "Expo", item = "Auto ETTR", value = 0},
            { menu = "Expo", item = "Dual ISO", value = 0},
            { menu = "Shoot", item = "Silent Picture", value = 0},
        }
    },
    {
        name = "ETTR",
        menus=
        {
            { menu = "Expo", item = "Auto ETTR", value = 1},
        }
    },
    {
        name = "DUAL",
        menus=
        {
            { menu = "Expo", item = "Auto ETTR", value = 0},
            { menu = "Expo", item = "Dual ISO", value = 1},
        }
    },
    {
        name = "BRAC",
        menus=
        {
            { menu = "Shoot", item = "Advanced Bracket", value = 1},
            { menu = "Expo", item = "Dual ISO", value = 0},
        }
    },
    {
        name = "FRSP",
        menus=
        {
            { menu = "Shoot", item = "Advanced Bracket", value = 0},
            { menu = "Shoot", item = "Silent Picture", value = 1},
        }
    }
}

event.keypress = function(key)
if keymenu.submenu["Turn On/Off"].value == "Off" then
return true  -- Toggler does nothing
elseif key == toggler  then -- act on a toggle
toggler_play = toggler_play + 1
if toggler_play > #toggler_presets then toggler_play = 1 end
for i,v in ipairs(toggler_presets[toggler_play].menus) do
menu.set(v.menu,v.item,v.value)
end
if toggler_play == 5 then -- check FRSP values
if camera.shutter.value < 0.2 or camera.shutter.value > 14 then
menu.set("Shoot","Silent Picture",0)
else
menu.set("Shoot","Silent Picture",1)
end
end
return false
end
end

lv.info
{
name = "Info 1",
priority = 100,
value = "",
update = function(this)
this.background = COLOR.BLUE
this.foreground = COLOR.YELLOW
if keymenu.submenu["Turn On/Off"].value == "On" then
this.value = toggler_presets[toggler_play].name
if toggler_play == 5 then -- then need to recheck FRSP values in case user changes shutter speed
if camera.shutter.value < 0.2 or camera.shutter.value > 14 then
this.foreground = COLOR.RED
menu.set("Shoot","Silent Picture",0)
else
this.foreground = COLOR.YELLOW
menu.set("Shoot","Silent Picture",1)
end
end
end
end
}

keymenu = menu.new
{
parent = "Shoot",
name = "Toggler",
help = "Toggle through various ML options",
depends_on = DEPENDS_ON.LIVEVIEW,
submenu =
{
{
name = "Turn On/Off",
help = "Switches the script on/off",
choices = {"On","Off"},
}
}
}

garry23

  • Contributor
  • Hero Member
  • *****
  • Posts: 1807
Re: Toggler: Update
« Reply #4 on: June 01, 2016, 10:36:51 AM »
Slight update  ;)

As I realized that I had not reset the Toggler menu items to their OFF state.

Code: [Select]
--[[
Still photography toggler script
Version 1.5 (should work on all ML enabled cameras with the Lua module)
Garry George June 2016
http://photography.grayheron.net/
Toggler script for ML settings.
Toggle through ML settings using the selected option, ie a button you rarely use.
Must be in LV.
--]]

-- Declare some variables
toggler_play = 1
toggler = 0

-- Change toggler value to your choice of button, eg KEY.RATE, KEY.UP, KEY.INFO or KEY.PLAY.
-- See http://davidmilligan.github.io/ml-lua/modules/constants.html for key constants
-- Default is KEY.RATE for non-EOSM cameras. EOSM self selects upper toggle on main dial as the EOSM doesn't have many buttons!
if camera.model_short == "EOSM" then toggler = KEY.UP else toggler = KEY.RATE end -- Change RATE to your choice

toggler_presets =
{
    {
        name = "OFF ", -- Toggler active but all ML Toggler menus turned off
        menus=
        {
            { menu = "Shoot", item = "Advanced Bracket", value = 0},
            { menu = "Expo", item = "Auto ETTR", value = 0},
            { menu = "Expo", item = "Dual ISO", value = 0},
            { menu = "Shoot", item = "Silent Picture", value = 0},
        }
    },
    {
        name = "ETTR",
        menus=
        {
            { menu = "Expo", item = "Auto ETTR", value = 1},
        }
    },
    {
        name = "DUAL",
        menus=
        {
            { menu = "Expo", item = "Auto ETTR", value = 0},
            { menu = "Expo", item = "Dual ISO", value = 1},
        }
    },
    {
        name = "BRAC",
        menus=
        {
            { menu = "Shoot", item = "Advanced Bracket", value = 1},
            { menu = "Expo", item = "Dual ISO", value = 0},
        }
    },
    {
        name = "FRSP",
        menus=
        {
            { menu = "Shoot", item = "Advanced Bracket", value = 0},
            { menu = "Shoot", item = "Silent Picture", value = 1},
        }
    }
}

event.keypress = function(key)
if keymenu.submenu["Enabled?"].value == "No" then
return true  -- Toggler does nothing and shows no menu states
elseif key == toggler  then -- act on a toggle
toggler_play = toggler_play + 1
if toggler_play > #toggler_presets then toggler_play = 1 end
for i,v in ipairs(toggler_presets[toggler_play].menus) do
menu.set(v.menu,v.item,v.value)
end
if toggler_play == 5 then -- check FRSP values
if camera.shutter.value < 0.2 or camera.shutter.value > 14 then
menu.set("Shoot","Silent Picture",0)
else
menu.set("Shoot","Silent Picture",1)
end
end
return false
end
end

lv.info
{
name = "Info 1",
priority = 100,
value = "",
update = function(this)
this.background = COLOR.BLUE
this.foreground = COLOR.YELLOW
if keymenu.submenu["Enabled?"].value == "Yes" then
this.value = toggler_presets[toggler_play].name
if toggler_play == 5 then -- then need to recheck FRSP values in case user changes shutter speed
if camera.shutter.value < 0.2 or camera.shutter.value > 14 then
this.foreground = COLOR.RED
menu.set("Shoot","Silent Picture",0)
else
this.foreground = COLOR.YELLOW
menu.set("Shoot","Silent Picture",1)
end
end
else
this.value = ""
end
end
}

keymenu = menu.new
{
parent = "Shoot",
name = "Toggler",
help = "Toggle through various ML options",
depends_on = DEPENDS_ON.LIVEVIEW,
submenu =
{
{
name = "Enabled?",
help = "Switches the script on/off",
choices = {"Yes","No"},
update = function(this) -- 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
end
}
}
}

dmilligan

  • Developer
  • Hero Member
  • *****
  • Posts: 3218
  • 60Da / 1100D / EOSM
Re: Toggler: Update
« Reply #5 on: June 01, 2016, 01:02:47 PM »
The lv.info update is still an inappropriate place to do what you are doing, same goes for menu update. If you want to change menu values based on shutter speed changing, then you should do it from an event that fires when the shutter speed changes. You can set property handler for this. For the menu one, use select instead of update (update runs frequently, select only runs when the user changes the value).

Also this:
Code: [Select]
if toggler_play == 5 then -- check FRSP values
makes it not 'generic' anymore. I have to have 5 presets and the 5th on and only the 5th one can be FRSP. Instead why not simply read the menu value of silent picture? That way one could simply modify 'presets' to their liking without having to change any other code.

garry23

  • Contributor
  • Hero Member
  • *****
  • Posts: 1807
Re: Toggler: Update
« Reply #6 on: June 01, 2016, 02:15:16 PM »
Cheers!

 :) :) :)

garry23

  • Contributor
  • Hero Member
  • *****
  • Posts: 1807
Re: Toggler: Update
« Reply #7 on: June 01, 2016, 03:23:44 PM »
David

I've got the handler working but I'm getting strange behavior.

Here is the code snippet

Code: [Select]
function property.SHUTTER:handler(value) -- shutter value changed
   if frsp then -- then need to recheck FRSP values in case user changes shutter speed
display.notify_box (value,3000)
if value < 0.2 or value > 14 then
menu.set("Shoot","Silent Picture",0)
else
menu.set("Shoot","Silent Picture",1)
end
end
end

I added the display.notify to check the shutter value.

I don't understand the units. At 1s I get 56 returned.

Can you help me understand.

Cheers

Garry

dmilligan

  • Developer
  • Hero Member
  • *****
  • Posts: 3218
  • 60Da / 1100D / EOSM
Re: Toggler: Update
« Reply #8 on: June 01, 2016, 04:33:50 PM »
Property handlers give you the raw value used by Canon firmware. If you want some nicer unit, use camera.shutter.<whatever>

garry23

  • Contributor
  • Hero Member
  • *****
  • Posts: 1807
Re: Toggler: Update
« Reply #9 on: June 01, 2016, 06:45:18 PM »
David

Thanks again for a very productive and educational day  :)

My Toggler script is now way past the Pareto point, ie I'm sure you could polish it further: but I'm happy with it  ;)

I took on all you said, other than the config suggestion  :-\

Here is the 'final' script:

Code: [Select]
--[[
Still photography toggler script
Version 1.6 (should work on all ML enabled cameras with the Lua module)
Garry George June 2016
http://photography.grayheron.net/
Toggler script for ML settings.
Toggle through ML settings using the selected option, ie a button you rarely use.
Must be in LV.
--]]

-- Declare some variables
toggler_play = 1
toggler = 0
frsp = false
frsp_ok = false

-- Change toggler value to your choice of button, eg KEY.RATE, KEY.UP, KEY.INFO or KEY.PLAY.
-- See http://davidmilligan.github.io/ml-lua/modules/constants.html for key constants
-- Default is KEY.RATE for non-EOSM cameras. EOSM self selects upper toggle on main dial as the EOSM doesn't have many buttons!
if camera.model_short == "EOSM" then toggler = KEY.UP else toggler = KEY.RATE end -- Change RATE to your choice

function property.SHUTTER:handler(value) -- Check if shutter value changed between toggles
if keymenu.submenu["Enabled?"].value == "Yes" and frsp then -- then need to recheck FRSP values in case user changes shutter speed
if camera.shutter.value < 0.2 or camera.shutter.value > 14 then
frsp_ok = false  -- outside FRSP range
menu.set("Shoot","Silent Picture",0)
else
frsp_ok = true -- Good to go with FRSP
menu.set("Shoot","Silent Picture",1)
end
end
end
toggler_presets =
{
    {
        name = "OFF ", -- Toggler active but all ML Toggler menus turned off
        menus=
        {
{ menu = "Shoot", item = "Advanced Bracket", value = 0},
{ menu = "Shoot", item = "Silent Picture", value = 0},
{ menu = "Expo", item = "Auto ETTR", value = 0},
{ menu = "Expo", item = "Dual ISO", value = 0},
        }
    },
    {
        name = "ETTR",
        menus=
        {
{ menu = "Expo", item = "Auto ETTR", value = 1},
        }
    },
    {
        name = "DUAL",
        menus=
        {
{ menu = "Expo", item = "Auto ETTR", value = 0},
{ menu = "Expo", item = "Dual ISO", value = 1},
        }
    },
    {
        name = "BRAC",
        menus=
        {
{ menu = "Shoot", item = "Advanced Bracket", value = 1},
{ menu = "Expo", item = "Dual ISO", value = 0},
        }
    },
    {
        name = "FRSP",
        menus=
        {
{ menu = "Shoot", item = "Silent Picture", value = 1},
{ menu = "Shoot", item = "Advanced Bracket", value = 0},

        }
    }
}
-- You can add other ML 'menu states' above

event.keypress = function(key)
if keymenu.submenu["Enabled?"].value == "No" then
return true  -- Toggler does nothing and shows no menu states
elseif key == toggler  then -- act on a toggle
toggler_play = toggler_play + 1
frsp = false -- assume FRSP not selected
if toggler_play > #toggler_presets then toggler_play = 1 end
for i,v in ipairs(toggler_presets[toggler_play].menus) do
menu.set(v.menu,v.item,v.value)
if v.item == "Silent Picture" and v.value == 1 then frsp = true end -- check if FRSP set to ON in this toggle
end
if frsp then -- check shutter values following toggle and FRSP requested
if camera.shutter.value < 0.2 or camera.shutter.value > 14 then
frsp_ok = false  -- outside FRSP range
menu.set("Shoot","Silent Picture",0)
else
frsp_ok = true -- Good to go with FRSP
menu.set("Shoot","Silent Picture",1)
end
end
return false
end
end

lv.info
{
name = "Info 1",
priority = 100,
value = "",
update = function(this)
this.background = COLOR.BLUE
this.foreground = COLOR.YELLOW
if keymenu.submenu["Enabled?"].value == "Yes" then
if frsp then -- FRSP requested then need to feedback FRSP shutter speed is OK or not
if not frsp_ok then this.foreground = COLOR.RED end
end
this.value = toggler_presets[toggler_play].name
else
this.value = ""
end
end
}

keymenu = menu.new
{
parent = "Shoot",
name = "Toggler",
help = "Toggle through various ML options",
depends_on = DEPENDS_ON.LIVEVIEW,
submenu =
{
{
name = "Enabled?",
help = "Switches the script on/off",
choices = {"Yes","No"},
update = function(this) -- 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
-- menu.close()
end
}
}
}

dmilligan

  • Developer
  • Hero Member
  • *****
  • Posts: 3218
  • 60Da / 1100D / EOSM
Re: Toggler: Update
« Reply #10 on: June 01, 2016, 07:25:30 PM »
One final suggestion, you might consider keeping your scripts somewhere like: https://gist.github.com/

That'll give you easy and simple version control amongst other things, and it'll be easier for other users to find the latest version (rather than searching through a forum thread).

garry23

  • Contributor
  • Hero Member
  • *****
  • Posts: 1807
Re: Toggler: Update
« Reply #11 on: June 01, 2016, 07:43:11 PM »
David

Thanks I'll look into that link.

Cheers

Garry

garry23

  • Contributor
  • Hero Member
  • *****
  • Posts: 1807
Re: Toggler: Update
« Reply #12 on: June 01, 2016, 08:53:34 PM »
David

I created a gist and uploaded two of my scripts  :)

https://gist.github.com/pigeonhill

Cheers

Garry