add scrollbar

This commit is contained in:
ruki
2020-11-28 00:42:19 +08:00
parent 11ee985740
commit 1f9076fbd7
6 changed files with 222 additions and 8 deletions

View File

@@ -42,6 +42,7 @@ action:register("ac_max",
"ac_on_selected",
"ac_on_clicked",
"ac_on_resized",
"ac_on_scrolled",
"ac_on_enter",
"ac_on_load",
"ac_on_save",

View File

@@ -40,7 +40,7 @@ function boxdialog:init(name, bounds, title)
self:text():bounds().ey = self._TEXT_EY
self:text():invalidate(true)
self:text():option_set("selectable", false)
self:text():option_set("progress", false)
self:text():option_set("scrollable", false)
-- insert box
self:panel():insert(self:box())

View File

@@ -45,7 +45,7 @@ function inputdialog:init(name, bounds, title)
self:text():bounds().ey = 1
self:text():invalidate(true)
self:text():option_set("selectable", false)
self:text():option_set("progress", false)
self:text():option_set("scrollable", false)
-- text changed
self:text():action_set(action.ac_on_text_changed, function (v)

211
src/ltui/scrollbar.lua Normal file
View File

@@ -0,0 +1,211 @@
---A cross-platform terminal ui library based on Lua
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- Copyright (C) 2015-2020, TBOOX Open Source Group.
--
-- @author ruki
-- @file scrollbar.lua
--
-- load modules
local log = require("ltui/base/log")
local view = require("ltui/view")
local event = require("ltui/event")
local curses = require("ltui/curses")
local action = require("ltui/action")
-- define module
local scrollbar = scrollbar or view()
-- init scrollbar
function scrollbar:init(name, bounds, vertical)
-- init view
view.init(self, name, bounds)
-- init bar attribute
self:charattr_set("black")
-- init bar vertical
self:vertical_set(vertical)
-- init progress
self:progress_set(0)
-- init character
self:char_set(' ')
end
-- get bar attribute
function scrollbar:charattr()
return self:attr("charattr")
end
-- set bar attribute, .e.g charattr_set("yellow onblue bold")
function scrollbar:charattr_set(attr)
return self:attr_set("charattr", attr)
end
-- get the current char attribute value
function scrollbar:charattr_val()
-- get text attribute
local charattr = self:charattr()
if not charattr then
return
end
-- no text background? use view's background
if self:background() and not charattr:find("on") then
charattr = charattr .. " on" .. self:background()
end
-- attempt to get the attribute value from the cache first
self._charattr = self._charattr or {}
local value = self._charattr[charattr]
if value then
return value
end
-- update the cache
value = curses.calc_attr(charattr:split("%s+"))
self._charattr[charattr] = value
return value
end
-- get bar character
function scrollbar:char()
return self:attr("char") or ' '
end
-- set bar character
function scrollbar:char_set(char)
if char ~= self:char() then
self:invalidate()
end
return self:attr_set("char", char)
end
-- is vertical bar?
function scrollbar:vertical()
return self:attr("vertical") or true
end
-- set bar vertical
function scrollbar:vertical_set(vertical)
return self:attr_set("vertical", vertical)
end
-- get bar progress
function scrollbar:progress()
return self:attr("progress") or 0
end
-- set bar progress, [0, 1]
function scrollbar:progress_set(progress)
if progress > 1 then
progress = 1
elseif progress < 0 then
progress = 0
end
if progress ~= self:progress() then
self:invalidate()
end
return self:attr_set("progress", progress)
end
-- get bar step width
function scrollbar:stepwidth()
return self:attr("stepwidth") or 0.1
end
-- set bar step width, [0, 1]
function scrollbar:stepwidth_set(stepwidth)
if stepwidth > 1 then
stepwidth = 1
elseif stepwidth < 0 then
stepwidth = 0
end
if stepwidth ~= self:stepwidth() then
self:invalidate()
end
return self:attr_set("stepwidth", stepwidth)
end
-- draw scrollbar
function scrollbar:on_draw(transparent)
-- draw background
view.on_draw(self, transparent)
-- compute bar range
local char = self:char()
local charattr = self:charattr_val()
local progress = self:progress()
local stepwidth = self:stepwidth()
local pb = progress
local pe = progress + stepwidth
if pe > 1 then
pb = 1 - stepwidth
pe = 1
end
-- draw bar
if self:vertical() then
local sb = math.floor(self:height() * pb)
local se = math.ceil(self:height() * pe)
if se > sb and se - sb < self:height() then
self:canvas():attr(charattr):move(0, sb):putchar(char, se - sb, true)
end
else
local sb = math.floor(self:width() * pb)
local se = math.ceil(self:width() * pe)
if se > sb and se - sb < self:width() then
self:canvas():attr(charattr):move(sb, 0):putchar(char, se - sb)
end
end
end
-- scroll bar, e.g. -1 * 0.1, 1 * 0.1
function scrollbar:scroll(steps)
steps = steps or 1
self:progress_set(self:progress() + steps * self:stepwidth())
self:action_on(action.ac_on_scrolled, self:progress())
end
-- on event
function scrollbar:on_event(e)
if e.type == event.ev_keyboard then
if self:vertical() then
if e.key_name == "Up" then
self:scroll(-1)
return true
elseif e.key_name == "Down" then
self:scroll(1)
return true
end
else
if e.key_name == "Left" then
self:scroll(-1)
return true
elseif e.key_name == "Right" then
self:scroll(1)
return true
end
end
end
end
-- return module
return scrollbar

View File

@@ -24,6 +24,8 @@ local view = require("ltui/view")
local label = require("ltui/label")
local event = require("ltui/event")
local curses = require("ltui/curses")
local action = require("ltui/action")
local scrollbar = require("ltui/scrollbar")
-- define module
local textarea = textarea or label()
@@ -37,8 +39,8 @@ function textarea:init(name, bounds, text)
-- mark as selectable
self:option_set("selectable", true)
-- enable progress
self:option_set("progress", true)
-- mark as scrollable
self:option_set("scrollable", true)
-- init start line
self._STARTLINE = 0
@@ -60,8 +62,8 @@ function textarea:on_draw(transparent)
self:canvas():attr(textattr):move(0, 0):putstrs(strs, self._STARTLINE + 1)
end
-- draw progress
if self:option("progress") then
-- draw scrollable
if self:option("scrollable") then
local tb = self._STARTLINE
local fator = self:height() / self._LINECOUNT
local sb = math.min(math.floor(tb * fator), self:height() - 1)

View File

@@ -47,8 +47,8 @@ function textedit:init(name, bounds, text)
self:option_set("mouseable", true)
self:action_set(action.ac_on_clicked, function () return true end)
-- disable progress
self:option_set("progress", false)
-- disable scrollbar
self:option_set("scrollable", false)
-- enable multiple line
self:option_set("multiline", true)