|
| 1 | +--[[ |
| 2 | + This file is part of darktable, |
| 3 | + copyright (c) 2023 Diederik ter Rahe |
| 4 | +
|
| 5 | + darktable is free software: you can redistribute it and/or modify |
| 6 | + it under the terms of the GNU General Public License as published by |
| 7 | + the Free Software Foundation, either version 3 of the License, or |
| 8 | + (at your option) any later version. |
| 9 | +
|
| 10 | + darktable is distributed in the hope that it will be useful, |
| 11 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | + GNU General Public License for more details. |
| 14 | +
|
| 15 | + You should have received a copy of the GNU General Public License |
| 16 | + along with darktable. If not, see <http://www.gnu.org/licenses/>. |
| 17 | +]] |
| 18 | +--[[ |
| 19 | +X-Touch Mini flexible encoder shortcuts |
| 20 | +
|
| 21 | +This script will create virtual sliders that are mapped dynamically to |
| 22 | +the most relevant sliders for the currently focused processing module. |
| 23 | +Tailored modules are color zones, tone equalizer, color calibration and |
| 24 | +mask manager properties. The script can easily be amended for other |
| 25 | +devices or personal preferences. Virtual "toggle" buttons can be created |
| 26 | +as well, that dynamically change meaning depending on current status. |
| 27 | +
|
| 28 | +USAGE |
| 29 | +* require this script from your main lua file |
| 30 | +* restart darktable |
| 31 | +* create shortcuts for each of the encoders on the x-touch mini |
| 32 | + to a virtual slider under lua/x-touch |
| 33 | + or import the following shortcutsrc file in the shortcuts dialog/preferences tab: |
| 34 | +
|
| 35 | +None;midi:CC1=lua/x-touch/knob 1 |
| 36 | +None;midi:CC2=lua/x-touch/knob 2 |
| 37 | +None;midi:CC3=lua/x-touch/knob 3 |
| 38 | +None;midi:CC4=lua/x-touch/knob 4 |
| 39 | +None;midi:CC5=lua/x-touch/knob 5 |
| 40 | +None;midi:CC6=lua/x-touch/knob 6 |
| 41 | +None;midi:CC7=lua/x-touch/knob 7 |
| 42 | +None;midi:CC8=lua/x-touch/knob 8 |
| 43 | +midi:E0=global/modifiers |
| 44 | +midi:F0=global/modifiers;ctrl |
| 45 | +midi:F#0=global/modifiers;alt |
| 46 | +midi:G#-1=iop/blend/tools/show and edit mask elements |
| 47 | +midi:A-1=iop/colorzones;focus |
| 48 | +midi:A#-1=iop/toneequal;focus |
| 49 | +midi:B-1=iop/colorbalancergb;focus |
| 50 | +midi:C0=iop/channelmixerrgb;focus |
| 51 | +]] |
| 52 | + |
| 53 | +local dt = require "darktable" |
| 54 | +local du = require "lib/dtutils" |
| 55 | + |
| 56 | +du.check_min_api_version("9.1.0", "x-touch") |
| 57 | + |
| 58 | +-- set up 8 mimic sliders with the same function |
| 59 | +for k = 1,8 do |
| 60 | + dt.gui.mimic("slider", "knob ".. k, |
| 61 | + function(action, element, effect, size) |
| 62 | + -- take the number from the mimic name |
| 63 | + local k = tonumber(action:sub(-1)) |
| 64 | + |
| 65 | + -- only operate in darkroom; return NAN otherwise |
| 66 | + if dt.gui.current_view() ~= dt.gui.views.darkroom then |
| 67 | + return 0/0 |
| 68 | + end |
| 69 | + |
| 70 | + local maskval = 0/0 |
| 71 | + if k < 8 then |
| 72 | + -- first try if the mask slider at that position is active |
| 73 | + local s = { "opacity", |
| 74 | + "size", |
| 75 | + "feather", |
| 76 | + "hardness", |
| 77 | + "rotation", |
| 78 | + "curvature", |
| 79 | + "compression" } |
| 80 | + maskval = dt.gui.action("lib/masks/properties/" .. s[k], |
| 81 | + element, effect, size) |
| 82 | + end |
| 83 | + -- if a value different from NAN is returned, the slider was active |
| 84 | + if maskval == maskval then |
| 85 | + return maskval |
| 86 | + |
| 87 | + -- try if colorzones module is focused; if so select element of graph |
| 88 | + elseif dt.gui.action("iop/colorzones", "focus") ~= 0 then |
| 89 | + which = "iop/colorzones/graph" |
| 90 | + local e = { "red", |
| 91 | + "orange", |
| 92 | + "yellow", |
| 93 | + "green", |
| 94 | + "aqua", |
| 95 | + "blue", |
| 96 | + "purple", |
| 97 | + "magenta" } |
| 98 | + element = e[k] |
| 99 | + |
| 100 | + -- if the tone equalizer is focused, |
| 101 | + -- select one of the sliders in the "simple" tab |
| 102 | + elseif dt.gui.action("iop/toneequal", "focus") ~= 0 then |
| 103 | + which ="iop/toneequal/simple/"..(k-9).." EV" |
| 104 | + |
| 105 | + -- if color calibration is focused, |
| 106 | + -- the last 4 knobs are sent there |
| 107 | + elseif dt.gui.action("iop/channelmixerrgb", "focus") ~= 0 |
| 108 | + and k >= 5 then |
| 109 | + -- knob 5 selects the active tab; pressing it resets to CAT |
| 110 | + if k == 5 then |
| 111 | + which = "iop/channelmixerrgb/page" |
| 112 | + element = "CAT" |
| 113 | + -- since the tab action is not a slider, |
| 114 | + -- the effects need to be translated |
| 115 | + if effect == "up" then effect = "next" |
| 116 | + elseif effect == "down" then effect = "previous" |
| 117 | + else effect = "activate" |
| 118 | + end |
| 119 | + else |
| 120 | + -- knobs 6, 7 and 8 are for the three color sliders on each tab |
| 121 | + which = "iop/focus/sliders" |
| 122 | + local e = { "1st", |
| 123 | + "2nd", |
| 124 | + "3rd" } |
| 125 | + element = e[k - 5] |
| 126 | + end |
| 127 | + |
| 128 | + -- the 4th knob is contrast; |
| 129 | + -- either colorbalance if it is focused, or filmic |
| 130 | + elseif dt.gui.action("iop/colorbalancergb", "focus") ~= 0 |
| 131 | + and k == 4 then |
| 132 | + which = "iop/colorbalancergb/contrast" |
| 133 | + |
| 134 | + -- in all other cases use a default selection |
| 135 | + else |
| 136 | + local s = { "iop/exposure/exposure", |
| 137 | + "iop/filmicrgb/white relative exposure", |
| 138 | + "iop/filmicrgb/black relative exposure", |
| 139 | + "iop/filmicrgb/contrast", |
| 140 | + "iop/crop/left", |
| 141 | + "iop/crop/right", |
| 142 | + "iop/crop/top", |
| 143 | + "iop/crop/bottom" } |
| 144 | + which = s[k] |
| 145 | + end |
| 146 | + |
| 147 | + -- now pass the element/effect/size to the selected slider |
| 148 | + return dt.gui.action(which, element, effect, size) |
| 149 | + end) |
| 150 | +end |
0 commit comments