Навигация по секциям списков

Здесь обсуждается всё, что касается макросов.
User avatar
John Doe
Бюрократ
Posts: 13801
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 72 times
Been thanked: 425 times
Contact:

Навигация по секциям списков

Post by John Doe »

С помощью предлагаемых макросов удобно перемещаться по секциям списков (разделённых сепараторами).
Работает в автодополнении, во всех меню (включая Главное и Пользовательское), в историях, листбоксах диалогов (на всякий случай).

Code: Select all

--http://forum.farmanager.com/viewtopic.php?f=15&t=9596
local F = far.Flags
local areas = "ShellAutoCompletion DialogAutoCompletion Menu UserMenu MainMenu Dialog"

local DELAY = 300
local function Jump(dir)
  local hDlg = far.AdvControl(F.ACTL_GETWINDOWINFO).Id
  local list = far.GetDlgItem(hDlg,1)[6]
  for i=list.SelectIndex+dir,dir<0 and 1 or #list, dir do
    if band(list[i].Flags,F.LIF_SEPARATOR)~=0 or i==1 then
      hDlg:send(F.DM_LISTSETCURPOS,1,{SelectPos=i,TopPos=i})
      return
    end
  end
  if mf.waitkey(DELAY)==mf.akey(1,1) then
    Keys(dir>0 and "Home" or "End")
  else
    mf.beep()
  end
end

Macro { description="Navigate to prev/next section";
  area=areas; key="/[LR]CtrlShift(Up|Down)/";
  id="1BAED6ED-E6F0-4313-BDC3-F8466BEEDB68";
  condition=function()
    return not Area.Dialog or (Dlg.ItemType==F.DI_LISTBOX)
  end;
  action=function()
    if Area.MainMenu and Object.Height==1 then
      Keys "Up"
    else
      Jump(mf.akey(1,1):match"Up$" and -1 or 1)
    end
  end;
}
Last edited by John Doe on Sat 07 Oct, 2017 10:32, edited 2 times in total.
Reason: doubletap to pass over edge
User avatar
John Doe
Бюрократ
Posts: 13801
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 72 times
Been thanked: 425 times
Contact:

Навигация по секциям списков

Post by John Doe »

Latest post of the previous page:

Эх, не хотелось усложнять..

А так?

Code: Select all

local F = far.Flags
local areas = "ShellAutoCompletion DialogAutoCompletion Menu UserMenu MainMenu Dialog"

local NOT_POSITIONABLE = bor(F.LIF_SEPARATOR,F.LIF_DISABLE,F.LIF_HIDDEN)
local DOUBLETAP_DELAY = 300
local AUTOREPEAT_DELAY = 200*1000
local lasttime = 0
local function Jump(dir)
  local ID = Area.Dialog and Dlg.CurPos or 1
  local sep_found,cur_positionable,last_able
  local hDlg = far.AdvControl(F.ACTL_GETWINDOWINFO).Id
  local list = far.GetDlgItem(hDlg,ID)[6]
  for i=list.SelectIndex+dir, dir<0 and 1 or #list, dir do
    local flags = list[i].Flags
    cur_positionable = band(flags,NOT_POSITIONABLE)==0
    last_able = cur_positionable and i or last_able
    if sep_found then
      if cur_positionable then
        hDlg:send(F.DM_LISTSETCURPOS,ID,{SelectPos=i,TopPos=sep_found-1})
        return
      end
    elseif band(flags,F.LIF_SEPARATOR)~=0 and band(flags,F.LIF_HIDDEN)==0 then
      sep_found = i
    end
  end
  if last_able and (last_able-list.SelectIndex>0)==(dir>0) then
    hDlg:send(F.DM_LISTSETCURPOS,ID,{SelectPos=last_able,TopPos=last_able-1})
  elseif far.FarClock()-lasttime>AUTOREPEAT_DELAY and mf.waitkey(DOUBLETAP_DELAY)==mf.akey(1,1) then
    Keys(dir>0 and "Home" or "End")
  else
    mf.beep()
  end
  lasttime = far.FarClock()
end

Macro { description="Navigate to prev/next section";
  area=areas; key="/[LR]CtrlShift(Up|Down)/";
  id="1BAED6ED-E6F0-4313-BDC3-F8466BEEDB68";
  condition=function()
    return not Area.Dialog or (Dlg.ItemType==F.DI_LISTBOX)
  end;
  action=function()
    if Area.MainMenu and Object.Height==1 then --HMenu
      Keys "Up"
    else
      Jump(mf.akey(1,1):match"Up$" and -1 or 1)
    end
  end;
}
Last edited by John Doe on Sat 14 Oct, 2017 12:57, edited 3 times in total.
User avatar
HaRT
Moderator
Posts: 10806
Joined: Tue 30 Aug, 2005 17:21
Has thanked: 220 times
Been thanked: 357 times

Навигация по секциям списков

Post by HaRT »

John Doe wrote: Mon 09 Oct, 2017 20:04А так?
Вроде работает ожидаемо в обоих случаях (с фильтром и без). Спасибо!
А сложно ли сделать, если сочетание CtrlShiftDown/CtrlShiftUp держать зажатым (для быстрого перемещения по длинному списку), чтобы не переходило через край? (Я такое поведение видел в Rockbox — на практике весьма удобно.)
Фар есть инструмент, а не нянька. © 2009 DrKnS
User avatar
John Doe
Бюрократ
Posts: 13801
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 72 times
Been thanked: 425 times
Contact:

Навигация по секциям списков

Post by John Doe »

Добавил.
User avatar
HaRT
Moderator
Posts: 10806
Joined: Tue 30 Aug, 2005 17:21
Has thanked: 220 times
Been thanked: 357 times

Навигация по секциям списков

Post by HaRT »

John Doe wrote: Mon 09 Oct, 2017 22:26Добавил.
Спасибо, с нижним краем работает.
А вот через верхний теперь переходит и по одиночному, и по зажатию (с фильтром и без). :(
Фар есть инструмент, а не нянька. © 2009 DrKnS
User avatar
John Doe
Бюрократ
Posts: 13801
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 72 times
Been thanked: 425 times
Contact:

Навигация по секциям списков

Post by John Doe »

Исправил
User avatar
HaRT
Moderator
Posts: 10806
Joined: Tue 30 Aug, 2005 17:21
Has thanked: 220 times
Been thanked: 357 times

Навигация по секциям списков

Post by HaRT »

John Doe wrote: Tue 10 Oct, 2017 07:03Исправил
Спасибо! Теперь вроде всё путём.
Фар есть инструмент, а не нянька. © 2009 DrKnS
User avatar
John Doe
Бюрократ
Posts: 13801
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 72 times
Been thanked: 425 times
Contact:

Навигация по секциям списков

Post by John Doe »

Из спортивного интереса ещё пару раз переделал скрипт. Финальный вариант:

Code: Select all

local F = far.Flags
local areas = "ShellAutoCompletion DialogAutoCompletion Menu UserMenu MainMenu Dialog"

local DOUBLETAP_DELAY = 300
local AUTOREPEAT_DELAY = 1000*100
local NOT_POSITIONABLE = bor(F.LIF_DISABLE,F.LIF_HIDDEN)
local lasttime = 0
local function Jump(dir)
  local dest
  local hDlg = far.AdvControl(F.ACTL_GETWINDOWINFO).Id
  local ID = Area.Dialog and Dlg.CurPos or 1
  local list = far.GetDlgItem(hDlg,ID)[6]
  local n,cur = #list,list.SelectIndex
  hDlg:send(F.DM_ENABLEREDRAW,0)
  for i=cur+dir, dir<0 and 1 or n, dir do
    if band(list[i].Flags,F.LIF_SEPARATOR)~=0 or i==1 or i==n then
      local pos = hDlg:send(F.DM_LISTSETCURPOS,ID,{SelectPos=i,TopPos=i-1})
      if pos~=i and (pos>i)~=(dir>0) then
        for i=i-dir, cur+dir, -1*dir do
          if band(list[i].Flags,NOT_POSITIONABLE)==0 then dest = i; break end
        end
        hDlg:send(F.DM_LISTSETCURPOS,ID,{SelectPos=dest or cur,TopPos=(dest or cur)-1})
      else
        dest = true
      end
      break
    end
  end
  hDlg:send(F.DM_ENABLEREDRAW,1)
  local time = far.FarClock()
  if not dest then
    mf.beep()
    if time-lasttime>AUTOREPEAT_DELAY and mf.waitkey(DOUBLETAP_DELAY)==mf.akey(1,1) then
      Keys(dir>0 and "Home" or "End")
    end
  end
  lasttime = time
end

Macro { description="Navigate to prev/next section";
  area=areas; key="/[LR]CtrlShift(Up|Down)/";
  id="1BAED6ED-E6F0-4313-BDC3-F8466BEEDB68";
  condition=function()
    return not Area.Dialog or (Dlg.ItemType==F.DI_LISTBOX)
  end;
  action=function()
    if Area.MainMenu and Object.Height==1 then --HMenu
      Keys "Up"
    else
      Jump(mf.akey(1,1):match"Up$" and -1 or 1)
    end
  end;
}
P.S.
Всё было бы значительно проще, если бы не DM_LISTSETCURPOS и DIF_LISTWRAPMODE.
User avatar
HaRT
Moderator
Posts: 10806
Joined: Tue 30 Aug, 2005 17:21
Has thanked: 220 times
Been thanked: 357 times

Навигация по секциям списков

Post by HaRT »

John Doe wrote: Sat 14 Oct, 2017 18:09Из спортивного интереса
Означает ли это, что функциональность ни прибавилась, ни убавилась?
Фар есть инструмент, а не нянька. © 2009 DrKnS
User avatar
John Doe
Бюрократ
Posts: 13801
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 72 times
Been thanked: 425 times
Contact:

Навигация по секциям списков

Post by John Doe »

Поведение изменилось в некоторых мелочах.
И возможны баги)
Post Reply

Return to “Обсуждение макросов”