Изменение кей-команд "на лету" (Changeble Hot Keys).

diggidon

Administrator
Команда форума
26 Май 2008
6.837
7.496
113
51
Днепр UA
Господа Рипероманы, встречайте новую, 100% уникальную фичу - Сhangeble Hot Keys. Ни один другой DAW гарантированно так не умеет.

Концепт был следующий:
1. Зарезервировать несколько клавиш на клавиатуре (в нашем случае это F1-F12), назначение которых менялось бы в зависимости от задачи, над которой вы сейчас работаете.
Первый пресет - Go to marker 1-12, второй пресет - Select track 1-12, третий пресет - работа со стреч маркерами, четвёртый... пятый... девяносто девятый...
2. Менять назначение этих клавиш (вызывать пресеты) что называется "на лету" - по нажатию другой клавиши, или соответствующей кнопки на тулбаре.
3. Сделать так, чтобы было видно, какой именно пресет сейчас используется. Принцип зависимой "кнопки-лампочки" - при включении одного пресета соответствующая кнопка загорается, остальные кнопки гаснут.

В качестве примера рассмотрим два пресета. Один - Go to marker 1-12, второй - Select track 1-12.
Changeble Hot Key 1.gif
В мультике всё видно - выбираем пресет кнопкой на тулбаре, жмём F1-F12.
Обратите внимание, как ведут себя кнопки тулбара. Если нажимать не мышкой, а привязанными к этим кнопкам клавишами, они будут вести себя точно так же.

1.Есть два Lua скрипта (которые в дальнейшем следует использовать как шаблон для создания своих собственных пресетов).
! Go to marker 1-12 (Changeble Key Preset).lua
! Select track 1-12 (Changeble Key Preset).lua

2.Помещаем их в папку \AppData\Roaming\REAPER\Scripts, импортируем в Рипер (Action List → ReaScript → Load...)
3. При запуске любого из этих скриптов в папке Scripts создадутся ещё 12 скриптов
ChanKey01.lua ... ChanKey12.lua, их тоже импортируеми в Рипер, и назначаем их на клавиши F1-F12.
4. Делаем собственные пресеты.
Для этого нужно сделать копию одного из двух шаблонных скриптов (! Go to marker 1-12 (Changeble Key Preset).lua или ! Select track 1-12 (Changeble Key Preset).lua), копию отредактировать, переименовать как удобно, импортировать в Рипер.
Standart Action.jpg SWS Custom Scripts.jpg
Если вы планируете использовать в пресете стандартные экшны Рипера, используйте в качестве шаблона
! Go to marker 1-12 (Changeble Key Preset).lua
Во всех остальных случаях (кастомы, SWS extension, скрипты) используйте в качестве шаблона
! Select track 1-12 (Changeble Key Preset).lua
Где посмотреть/скопировать Command ID нужного экшна/кастома/скрипта:
Command ID.jpg

5. Привязываем вновь созданные и импортированные скрипты-пресеты к кнопкам на тулбаре. При желании, назначаем на каждый скрипт-пресет кнопку на клавиатуре или миди-контроллере.
Собсно, всё.
Проверено, работает, летает...)))
Огромное, просто ОГРОМЕННОЕ СПАСИБИЩЕ Саше Олейнику @Aleksandr Oleynik за реализацию этого проекта! Ну, и мне немножко (за то, что повыносил ему мозг своими техзаданиями :)).

P.S. Безусловно мы понимаем, что процедура создания своих собственных пресетов, мягко говоря, абсолютно не юзер френдли, особенно для не очень подготовленного пользователя (впрочем, сам процесс работы с уже готовыми пресетами - это просто огонь).
Поэтому в идеале очень хотелось бы прикрутить ко всему этому делу какой-нибудь понятный юзер интерфейсик - именно для создания своих собственных пресетов. Типа, жмём Create User Preset → выплывает 12 кнопок → жмём на каждую кнопку, выбираем нужный экшн → Save As... → погнали.
И если к этому делу подключатся наши гуру-скриптописатели (например, @@Michael, @EUGEN27771), мы будем очень рады.
 

Вложения

Сама возможность данной фичи уже обсуждалась ранее -
http://rmmedia.ru/threads/118091/page-11#post-1950968
И достаточно бурно пообсуждалась.
Но по скольку, так сказать "Реального Заказчика" не появилось ( с реальной необходимостью довести всё до работающих скриптов) - то тормознулость тогда. Пару запросов на подобную фичу возникали от разных Форумчан и после этого.
Но вот тут Пан Дигидон загорелся не на шутку - ну и - вышло то, что вышло.
Если Фича будет восстребованна, я подумаю как её сделать более Юзабилити.
Ну и понятно, что без помощи @@@Michael, @@EUGEN27771 не справлюсь!
 
Последнее редактирование:
еще тот "гуру", я скорее сдуру-скриптописатель(это я про себя только).
С чего ты скриптописатель, не важно - но то, что умеешь ты, мне пока и не снилось :)

А что надо, если конкретнее?
Нужно придумать механизм автоматической перезаписи команд при создании нового Скрипта-Пресета для новой группы хоткеев.
Сейчас ID каждого из Экшинов (Кастом Экшинов) нужно ручками вписывать (переписывать) в новый Скрипт-Пресет.
А было бы круто сделать некое GUI, в котором было бы -
1. 12 кнопок, нажимая на которые возникал бы Action List - выбираешь Экшин, делаешь Copy selected action command ID - и ID попадает в таблицу скрипта (может и как-то иначе, но так, чтоб любому "дундуку было ясно что делать".
PS: И ещё нужно бы на них шот каты из скрипта иметь возможность назначать :(
2. И большая кнопка - "Создать и зарегистрировать новый Скрипт-Пресет для Группы Хоткеев" (ну или по проще назвать :) ) - нажал на неё, скрипт предложил ввести Имя Скрипта и все данные из таблиц c ID в нужные места записал. ну и сообщил, что какие-то из 12 ячеек остались пустыми (и учёл это в скрипте).
PS: И тут тоже засада - нужно и эти скрипты вешать на кнопки в Тулюаре и/или на хоткеи назначать иметь возможность :(
[DOUBLEPOST=1458649438,1458648435][/DOUBLEPOST]PS: В общем, чтоб функционал получился - "для солдатов и матросов" - нужно долго продумывать и много писать.
А сейчас -
делаешь дубликат скрипта, подменяешь в его начале ID-шники на новые по каждой из 12-и команд, сохраняешь, добавляешь на Тулбар и пользуешься.
Кому реально нужно - на мой взгляд разберуться.
Вот Женя же разобрался, не умея писать скрипты ВООБЩЕ.
 
А что надо, если конкретнее?

Ну если совсем для "пионера", то как-то так:
в идеале очень хотелось бы прикрутить ко всему этому делу какой-нибудь понятный юзер интерфейсик - именно для создания своих собственных пресетов. Типа, жмём Create User Preset → выплывает 12 кнопок → жмём на каждую кнопку, выбираем нужный экшн → Save As... → погнали.
Это как оно должно нмв выглядеть. Технические детали Саша описал.

Хотя мне, скажу честно, и так офигенно, потому что мнем это было ОЧЕНЬ нужно. Один раз скрипт-пресет сделал - и забыл, а пользуешься им потом постоянно, и с большим комфортом...
Но неподготовленный юзер запросто может обломаться именно на этапе создания своего скрипта-пресета, поэтому какую-нибудь понятную рамочку-табличку прикрутить хотелось бы.
 
Женя, чтоб совсем для "не в теме" - прийдётся Очень много делать и не факт, что возможно, например Action ID подтянуть в скрипт при выборе Action в Action List.
 
Может быть сделаю, если будет время, пока другие интересные темы есть, только экшн придется руками вставлять в диалог.
В принципе, сделать и Вы можете, могу дать кнопки, а там дальше цеплять можно что угодно.
В общем, вот простые кнопки,
PHP:
--------------------------------------------------------------------------------
---   Simple Element Class   ---------------------------------------------------
--------------------------------------------------------------------------------
local Element = {}
function Element:new(x,y,w,h, r,g,b,a, lbl,fnt,fnt_sz, norm_val)
    local elm = {}
    elm.def_xywh = {x,y,w,h,fnt_sz} -- its default coord,used for Zoom etc
    elm.x, elm.y, elm.w, elm.h = x, y, w, h
    elm.r, elm.g, elm.b, elm.a = r, g, b, a
    elm.lbl, elm.fnt, elm.fnt_sz  = lbl, fnt, fnt_sz
    elm.norm_val = norm_val
    ------
    setmetatable(elm, self)
    self.__index = self
    return elm
end
--------------------------------------------------------------
--- Function for Child Classes(args = Child,Parent Class) ----
--------------------------------------------------------------
function extended(Child, Parent)
     setmetatable(Child,{__index = Parent})
end
--------------------------------------------------------------
---   Element Class Methods(Main Methods)   ------------------
--------------------------------------------------------------
function Element:update_xywh()
  if not Z_w or not Z_h then return end -- return if zoom not defined
  if Z_w>0.5 and Z_w<3 then
   self.x, self.w = math.ceil(self.def_xywh[1]* Z_w) , math.ceil(self.def_xywh[3]* Z_w) --upd x,w
  end
  if Z_h>0.5 and Z_h<3 then
   self.y, self.h = math.ceil(self.def_xywh[2]* Z_h) , math.ceil(self.def_xywh[4]* Z_h) --upd y,h
  end
  if Z_w>0.5 or Z_h>0.5  then --fix it!--
     self.fnt_sz = math.max(9,self.def_xywh[5]* (Z_w+Z_h)/2)
     self.fnt_sz = math.min(22,self.fnt_sz)
  end    
end
--------
function Element:pointIN(p_x, p_y)
  return p_x >= self.x and p_x <= self.x + self.w and p_y >= self.y and p_y <= self.y + self.h
end
--------
function Element:mouseIN()
  return gfx.mouse_cap&1==0 and self:pointIN(gfx.mouse_x,gfx.mouse_y)
end
--------
function Element:mouseDown()
  return gfx.mouse_cap&1==1 and self:pointIN(mouse_ox,mouse_oy)
end
--------
function Element:mouseClick()
  return gfx.mouse_cap&1==0 and last_mouse_cap&1==1 and
  self:pointIN(gfx.mouse_x,gfx.mouse_y) and self:pointIN(mouse_ox,mouse_oy)      
end
--------
function Element:draw_frame()
  local x,y,w,h  = self.x,self.y,self.w,self.h
  gfx.rect(x, y, w, h, 0)--frame1
  gfx.roundrect(x, y, w-1, h-1, 3, true)--frame2      
end
--------------------------------------------------------------------------------
---   Create Element Child Classes(Button,Slider,Knob)   -----------------------
--------------------------------------------------------------------------------
local Button ={}; local Knob ={}; local Slider ={};
  extended(Button, Element)
  extended(Knob,   Element)
  extended(Slider, Element)
---Create Slider Child Classes(V_Slider,H_Slider)----
local H_Slider ={}; local V_Slider ={};
  extended(H_Slider, Slider)
  extended(V_Slider, Slider)

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
---   Button Class Methods   ---------------------------------------------------
--------------------------------------------------------------------------------
function Button:draw_lbl()
    local x,y,w,h  = self.x,self.y,self.w,self.h
    local fnt,fnt_sz = self.fnt, self.fnt_sz
    --Draw btn lbl(text)--
      gfx.set(0.7, 1, 0, 1)--set label color
      gfx.setfont(1, fnt, fnt_sz);--set label fnt
        local lbl_w, lbl_h = gfx.measurestr(self.lbl)
        gfx.x = x+(w-lbl_w)/2; gfx.y = y+(h-lbl_h)/2
        gfx.drawstr(self.lbl)
end
---------------------
function Button:draw()
    self:update_xywh()--Update xywh(if wind changed)
    local x,y,w,h  = self.x,self.y,self.w,self.h
    local r,g,b,a  = self.r,self.g,self.b,self.a
    ---Get L_mouse state--
          --in element--
          if self:mouseIN() then a=a+0.1 end
          --in elm L_down--
          if self:mouseDown() then a=a+0.2 end
          --in elm L_up(released and was previously pressed)--
          if self:mouseClick() then --[[self.onClick()]] end
    --Draw btn(body,frame)--
    gfx.set(r,g,b,a)--set btn color
    gfx.rect(x,y,w,h,true)--body
    self:draw_frame()
    ------------------------
    self:draw_lbl()
end
-------------------------------------------------
----Objects--------------------------------------
-------------------------------------------------
local btn1 = Button:new(20,  20,50,50,  0.7,0.3,0.3,0.5, "B1","Arial",20 )
local btn2 = Button:new(80,  20,50,50,  0.7,0.3,0.3,0.5, "B2","Arial",20 )
local btn3 = Button:new(140, 20,50,50,  0.7,0.3,0.3,0.5, "B3","Arial",20 )
local btn4 = Button:new(20,  80,50,50,  0.3,0.7,0.3,0.5, "B4","Arial",20 )
local btn5 = Button:new(80,  80,50,50,  0.3,0.7,0.3,0.5, "B5","Arial",20 )
local btn6 = Button:new(140, 80,50,50,  0.3,0.7,0.3,0.5, "B6","Arial",20 )
local Button_TB = {btn1,btn2,btn3,btn4,btn5,btn6}

------------------------------------------------
------------------------------------------------
function DRAW()
for key,btn in pairs(Button_TB) do btn:draw() end
end

--------------------------------------------------------------------------------
--Init--------------------------------------------------------------------------
--------------------------------------------------------------------------------
function Init()
--Some gfx Wnd Default Values--------------
local R,G,B = 20,20,20        --0..255 form
Wnd_bgd = R + G*256 + B*65536 --red+green*256+blue*65536
Wnd_Title,Wnd_W,Wnd_H,Wnd_Dock,Wnd_X,Wnd_Y = "TEST", 210,150, 0,100,320
--Init window------------------------------
gfx.clear = Wnd_bgd      
gfx.init( Wnd_Title, Wnd_W,Wnd_H, Wnd_Dock, Wnd_X,Wnd_Y )
--Mouse--
last_mouse_cap = 0
last_x, last_y = 0, 0
end
-------------------------
--Mainloop---------------
function mainloop()
Z_w,Z_h = gfx.w/Wnd_W, gfx.h/Wnd_H
if gfx.mouse_cap&1==1 and last_mouse_cap&1==0 then
    mouse_ox, mouse_oy = gfx.mouse_x, gfx.mouse_y
end
Ctrl  = gfx.mouse_cap&4==4
Shift = gfx.mouse_cap&8==8
----------------------
--DRAW,MAIN function--
   DRAW()--Main()
----------------------
----------------------
last_mouse_cap = gfx.mouse_cap
last_x, last_y = gfx.mouse_x, gfx.mouse_y
char = gfx.getchar()
if char~=-1 then reaper.defer(mainloop) end --defer
-----------
gfx.update()
-----------
end
---------------------------------------
---------------------------------------
Init()
mainloop()
Добавить,удалить,поменять можно здесь
Снимок.PNG
Как добавить действия Вы знаете
 
Последнее редактирование:
пока другие интересные темы есть
Это очень здорово! Ждём! :)

Как добавить действия Вы знаете
Как ID брать, выбирая Action из списка экшинов? Или просто - скопировал ID - вставил в диалоговое окно User Input?
В общем ты так и написал -
только экшн придется руками вставлять в диалог.
 
Не забывайте, что там ещё одна "засада" - разные шаблонные скрипты под стандартные экшны и под кастомы/цикл/SWS/скрипты. Как с этим быть?
Я, повторюсь, довольно быстро разобрался, в том числе и как сделать микс-скрипт (часть штатных, часть кастомов/цикл/SWS/скриптов).
Но мы же думаем о функционале для не очень продвинутых юзеров... Чтобы не отпугнуло... Фича-то реально обалденная получилась, у меня вчера реально крышу снесло от вновь открывшихся возможностей - 10 штук пресетов себе уже запилил, и то ли ещё будет))
 
  • Like
Реакции: AntonCorea
Наверное, только так.. других вариантов я не знаю.
А ведь где-то же хранится этот список наименований Action и их ID!
[DOUBLEPOST=1458666854,1458666741][/DOUBLEPOST]
Не забывайте, что там ещё одна "засада" - разные шаблонные скрипты под стандартные экшны и под кастомы/цикл/SWS/скрипты. Как с этим быть?
Это какраз не сложно! Патерн, который будет отдуплять чисто цифровой ID от цифро-буквенного и соответственно использовать разные шаблоны команд.
 
  • Like
Реакции: diggidon
Вот Женя же разобрался, не умея писать скрипты ВООБЩЕ.
Ну не совсем так, что-то там я наваял... :rolleyes:
http://rmmedia.ru/threads/107757/#post-1890890
Впрочем, да, это действительно не скриптописание, а так, баловство... Написать скрипт - это не портировать кастом в eel.
 
Впрочем, да, это действительно не скриптописание, а так, баловство... Написать скрипт - это не портировать кастом в eel.
Не скромничай, в любом случае ты совсем не годишься на роль шитконтрола для юзабилити, ты и между строк читать умеешь! :)
 
  • Like
Реакции: diggidon
Нет слов, кроме восхищения

Идеально для тех, кто использует VST-кнопки, можно наконец реализовать добавление эффекта на дорожку или на айтем в одной кнопке.

Аплодирую!
 
  • Like
Реакции: Furqat
как прикрепить к получившимся кнопкам действия
Сами кнопки получились - это уже хорошо. Это очень старый скрипт, но он наиболее простой - в этом и фокус, оказывается.
Раскомментировать эту строку if self:mouseClick() then --[[self.onClick()]] end - убрать двойные кв. скобки, я спецом закомментил, хотя нужно было иначе сделать.
Должно быть так - if self:mouseClick() and self.onClick then self.onClick() end
Теперь, каждой кнопке можно дать свое действие - в общем случае - любая функция, а в Вашем конкретном - по такому принципу:
--- Исправлено ---
-- Methods -----
command = 1007 -- Это только пример, можете писать напрямую вместо command!!!
btn1.onClick = function() reaper.Main_OnCommand(command, 0) end
btn2.onClick = ...
btn3.onClick = ...
...etc

Где command - это command ID - смотреть в списке экшнов.
 
Последнее редактирование:
  • Like
Реакции: RJ Baker
@EUGEN27771, спасибо за ответ, но, извините не все понял, написал в личку. Сделал много кнопочек осталось их научится назначать..
 
@RJ Baker, поправил, моя вина(писал по памяти, ошибся).
Верхнюю строку( if self:mouseClick() ... ) тоже исправьте, чтобы на "пустые" кнопки не было ошибок.
 
  • Like
Реакции: RJ Baker
@EUGEN27771, да, теперь работает, большое спасибо! ура!
Но.. только со стандартными экшенами, а там где ID скриптов-кастомных экшенов я по аналогии с выложенным выше скриптом Select track 1-12 (Changeble Key Preset).lua пытался что то сделать, но выдает ощибки, подскажите как правильно описать command ID в данном случае?
Нужно ли вводить какую то переменную типа
local btn2 = "_SWS_SEL1" или как то еще?
 
Спасибо, вам ребята @EUGEN27771, @lil-burn, за подсказки: я хоть и освоил как то для себя WALTER, но тут совсем другой уровень, а я не программист совсем. НЕ понимаю - все ж должно работать уже, 1-я кнопка отзывается как надо, а вторая все равно выдает "attempt to call a nil value (global 'NamedCommandLookup'" - ну простите туповат я наверное, обещаю, как разберусь с этим скриптом, больше доставать вопросами не стану!
Чессслово!))
Код:
--------------------------------------------------------------------------------
---   Simple Element Class   ---------------------------------------------------
--------------------------------------------------------------------------------
local Element = {}
function Element:new(x,y,w,h, r,g,b,a, lbl,fnt,fnt_sz, norm_val)
    local elm = {}
    elm.def_xywh = {x,y,w,h,fnt_sz} -- its default coord,used for Zoom etc
    elm.x, elm.y, elm.w, elm.h = x, y, w, h
    elm.r, elm.g, elm.b, elm.a = r, g, b, a
    elm.lbl, elm.fnt, elm.fnt_sz  = lbl, fnt, fnt_sz
    elm.norm_val = norm_val
    ------
    setmetatable(elm, self)
    self.__index = self
    return elm
end
--------------------------------------------------------------
--- Function for Child Classes(args = Child,Parent Class) ----
--------------------------------------------------------------
function extended(Child, Parent)
     setmetatable(Child,{__index = Parent})
end
--------------------------------------------------------------
---   Element Class Methods(Main Methods)   ------------------
--------------------------------------------------------------
function Element:update_xywh()
  if not Z_w or not Z_h then return end -- return if zoom not defined
  if Z_w>0.5 and Z_w<3 then
   self.x, self.w = math.ceil(self.def_xywh[1]* Z_w) , math.ceil(self.def_xywh[3]* Z_w) --upd x,w
  end
  if Z_h>0.5 and Z_h<3 then
   self.y, self.h = math.ceil(self.def_xywh[2]* Z_h) , math.ceil(self.def_xywh[4]* Z_h) --upd y,h
  end
  if Z_w>0.5 or Z_h>0.5  then --fix it!--
     self.fnt_sz = math.max(9,self.def_xywh[5]* (Z_w+Z_h)/2)
     self.fnt_sz = math.min(22,self.fnt_sz)
  end  
end
--------
function Element:pointIN(p_x, p_y)
  return p_x >= self.x and p_x <= self.x + self.w and p_y >= self.y and p_y <= self.y + self.h
end
--------
function Element:mouseIN()
  return gfx.mouse_cap&1==0 and self:pointIN(gfx.mouse_x,gfx.mouse_y)
end
--------
function Element:mouseDown()
  return gfx.mouse_cap&1==1 and self:pointIN(mouse_ox,mouse_oy)
end
--------
function Element:mouseClick()
  return gfx.mouse_cap&1==0 and last_mouse_cap&1==1 and
  self:pointIN(gfx.mouse_x,gfx.mouse_y) and self:pointIN(mouse_ox,mouse_oy)    
end
--------
function Element:draw_frame()
  local x,y,w,h  = self.x,self.y,self.w,self.h
  gfx.rect(x, y, w, h, 0)--frame1
  gfx.roundrect(x, y, w-1, h-1, 3, true)--frame2    
end
--------------------------------------------------------------------------------
---   Create Element Child Classes(Button,Slider,Knob)   -----------------------
--------------------------------------------------------------------------------
local Button ={}; local Knob ={}; local Slider ={};
  extended(Button, Element)
  extended(Knob,   Element)
  extended(Slider, Element)
---Create Slider Child Classes(V_Slider,H_Slider)----
local H_Slider ={}; local V_Slider ={};
  extended(H_Slider, Slider)
  extended(V_Slider, Slider)

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
---   Button Class Methods   ---------------------------------------------------
--------------------------------------------------------------------------------
function Button:draw_lbl()
    local x,y,w,h  = self.x,self.y,self.w,self.h
    local fnt,fnt_sz = self.fnt, self.fnt_sz
    --Draw btn lbl(text)--
      gfx.set(0.7, 1, 0, 1)--set label color
      gfx.setfont(1, fnt, fnt_sz);--set label fnt
        local lbl_w, lbl_h = gfx.measurestr(self.lbl)
        gfx.x = x+(w-lbl_w)/2; gfx.y = y+(h-lbl_h)/2
        gfx.drawstr(self.lbl)
end
---------------------
function Button:draw()
    self:update_xywh()--Update xywh(if wind changed)
    local x,y,w,h  = self.x,self.y,self.w,self.h
    local r,g,b,a  = self.r,self.g,self.b,self.a
    ---Get L_mouse state--
          --in element--
          if self:mouseIN() then a=a+0.1 end
          --in elm L_down--
          if self:mouseDown() then a=a+0.2 end
          --in elm L_up(released and was previously pressed)--
          if self:mouseClick() and self.onClick then self.onClick() end
    --Draw btn(body,frame)--
    gfx.set(r,g,b,a)--set btn color
    gfx.rect(x,y,w,h,true)--body
    self:draw_frame()
    ------------------------
    self:draw_lbl()
end
-------------------------------------------------
----Objects--------------------------------------
-------------------------------------------------
local btn1 = Button:new(20,  20,50,50,  0.7,0.3,0.3,0.5, "B1","Arial",20 )
local btn2 = Button:new(80,  20,50,50,  0.7,0.3,0.3,0.5, "B2","Arial",20 )
local btn3 = Button:new(140, 20,50,50,  0.7,0.3,0.3,0.5, "B3","Arial",20 )
local btn4 = Button:new(200,  20,50,50,  0.7,0.3,0.3,0.5, "B4","Arial",20 )
local btn5 = Button:new(260,  20,50,50,  0.7,0.3,0.3,0.5, "B5","Arial",20 )
local btn6 = Button:new(320, 20,50,50,  0.7,0.3,0.3,0.5, "B6","Arial",20 )
local btn7 = Button:new(20,  80,50,50,  0.3,0.7,0.3,0.5, "B7","Arial",20 )
local btn8 = Button:new(80,  80,50,50,  0.3,0.7,0.3,0.5, "B8","Arial",20 )
local btn9 = Button:new(140, 80,50,50,  0.3,0.7,0.3,0.5, "B9","Arial",20 )
local btn10 = Button:new(200,  80,50,50,  0.7,0.3,0.3,0.5, "B10","Arial",20 )
local btn11 = Button:new(260,  80,50,50,  0.7,0.3,0.3,0.5, "B11","Arial",20 )
local btn12 = Button:new(320,  80,50,50,  0.7,0.3,0.3,0.5, "B12","Arial",20 )
local btn13 = Button:new(20, 140,50,50,  0.7,0.3,0.3,0.5, "B13","Arial",20 )
local btn14 = Button:new(80,  140,50,50,  0.7,0.3,0.3,0.5, "B14","Arial",20 )
local btn15 = Button:new(140,  140,50,50,  0.7,0.3,0.3,0.5, "B15","Arial",20 )
local btn16 = Button:new(200, 140,50,50,  0.7,0.3,0.3,0.5, "B16","Arial",20 )
local btn17 = Button:new(260,  140,50,50,  0.3,0.7,0.3,0.5, "B17","Arial",20 )
local btn18 = Button:new(320,  140,50,50,  0.3,0.7,0.3,0.5, "B18","Arial",20 )

local Button_TB = {btn1,btn2,btn3,btn4,btn5,btn6,btn7,btn8,btn9,btn10,btn11,btn12,btn13,btn14,btn15,btn16,btn17,btn18}

btn1.onClick = function() reaper.Main_OnCommand(40007, 0) end
btn2.onClick = function() reaper.Main_OnCommand(NamedCommandLookup("_RS73b2fd94028f6345e90b72b4d8a636681c04f5f0"), 0) end

------------------------------------------------
------------------------------------------------
function DRAW()
for key,btn in pairs(Button_TB) do btn:draw() end
end

--------------------------------------------------------------------------------
--Init--------------------------------------------------------------------------
--------------------------------------------------------------------------------
function Init()
--Some gfx Wnd Default Values--------------
local R,G,B = 10,10,25 --0..255 form
Wnd_bgd = R  + G*256 + B*65536 --red +green*256+blue*65536
Wnd_Title,Wnd_W,Wnd_H,Wnd_Dock,Wnd_X,Wnd_Y = "18 buttons", 390,210,0,100,320
--Init window------------------------------
gfx.clear = Wnd_bgd    
gfx.init( Wnd_Title, Wnd_W,Wnd_H, Wnd_Dock, Wnd_X,Wnd_Y )
--Mouse--
last_mouse_cap = 0
last_x, last_y = 0, 0
end
-------------------------
--Mainloop---------------
function mainloop()
Z_w,Z_h = gfx.w/Wnd_W, gfx.h/Wnd_H
if gfx.mouse_cap&1==1 and last_mouse_cap&1==0 then
    mouse_ox, mouse_oy = gfx.mouse_x, gfx.mouse_y
end
Ctrl  = gfx.mouse_cap&4==4
Shift = gfx.mouse_cap&8==8
----------------------
--DRAW,MAIN function--
   DRAW()--Main()
----------------------
----------------------
last_mouse_cap = gfx.mouse_cap
last_x, last_y = gfx.mouse_x, gfx.mouse_y
char = gfx.getchar()
if char~=-1 then reaper.defer(mainloop) end --defer
-----------
gfx.update()
-----------
end
---------------------------------------
---------------------------------------
Init()
mainloop()
И еще может объясните - почему кнопки 7-9 и 17-18 не меняют цвет они же ничем вроде бы не отличаются...
Мне понравилась сама идея - обойти ограничение Рипера в 16 тулбаров... ну и т.д. А так я ни на что не претендую, чисто для себя решение хочу допилить.
 
Нужно придумать механизм автоматической перезаписи команд при создании нового Скрипта-Пресета для новой группы хоткеев.
Не вникал глубоко в суть предоставленных скриптов и механизма решения данной задачи, так как не успел пока ознакомится с ReaScripts и API Риппера.
Но осмелюсь дать весьма скромный совет по поводу упрощения для "юзера" процесса настройки собственных пресетов.
Вместо громоздкости и сложностей в реализации интерфейса, можно пойти другим проверенным в сходных задачах путем - читать конфигурации пресетов из INI-файла. Который пользователю создать будет проще, нежели вписывать ID непосредственно в код скрипта.

Например:
Код:
[Имя Пресета 1]
Key_1=ID
Key_2=ID
Key_n=ID
[Имя Пресета 2]
...
 
Странно, что все забыли про такую штуку. Как думаете, если Джастину показать, то он запилит её в основной функционал?
 
@vitalker, я поддерживаю!
Уже давно на кокосовом форуме поднимался вопрос про создание контекстнозависимых хоткеев или в зависимости от выбраной задачи, но за эту тему как-то тоже забыли.
 
А я вовсю юзаю, не дожидаясь Джастина.
У меня уже штук 10 разных сетов, из которых 3 в активном ежедневном использовании
З.Ы. Каждый раз вспоминаю @Aleksandr Oleynik "незлым тихим словом"))) © Т. Г. Шевченко.
 

Сейчас просматривают