add demo menu widget in new ui framework

pull/2/merge
Qingping Hou 12 years ago
parent df1c8814ea
commit b47d5b76eb

@ -52,18 +52,23 @@ function FocusManager:onFocusMove(args)
local current_item = self.layout[self.selected.y][self.selected.x]
while true do
if self.selected.y + dy > #self.layout
or self.selected.y + dy < 1
or self.selected.x + dx > #self.layout[self.selected.y]
if self.selected.x + dx > #self.layout[self.selected.y]
or self.selected.x + dx < 1 then
break -- abort when we run into borders
break -- abort when we run into horizontal borders
end
-- move cyclic in vertical direction
if self.selected.y + dy > #self.layout then
self.selected.y = 1
elseif self.selected.y + dy < 1 then
self.selected.y = #self.layout
else
self.selected.y = self.selected.y + dy
end
self.selected.x = self.selected.x + dx
self.selected.y = self.selected.y + dy
if self.layout[self.selected.y][self.selected.x] ~= current_item
and not self.layout[self.selected.y][self.selected.x].is_inactive then
or not self.layout[self.selected.y][self.selected.x].is_inactive then
-- we found a different object to focus
current_item:handleEvent(Event:new("Unfocus"))
self.layout[self.selected.y][self.selected.x]:handleEvent(Event:new("Focus"))
@ -171,7 +176,7 @@ function ConfirmBox:init()
face = Font:getFace("cfont", 30),
width = self.width,
},
VerticalSpan:new{ width = 20 },
VerticalSpan:new{ width = 10 },
HorizontalGroup:new{
ok_button,
HorizontalSpan:new{ width = 10 },
@ -184,7 +189,6 @@ function ConfirmBox:init()
end
function ConfirmBox:onClose()
self:cancel_callback()
UIManager:close(self)
return true
end
@ -229,7 +233,7 @@ function InfoMessage:init()
file = "resources/info-i.png"
},
HorizontalSpan:new{ width = 10 },
TextWidget:new{
TextBoxWidget:new{
text = self.text,
face = Font:getFace("cfont", 30)
}
@ -251,3 +255,276 @@ function InfoMessage:onAnyKeyPressed()
UIManager:close(self)
return true
end
--[[
Widget that displays a shortcut icon for menu item
]]
ItemShortCutIcon = WidgetContainer:new{
width = 22,
height = 22,
key = nil,
bordersize = 2,
}
function ItemShortCutIcon:init()
if not self.key then
return
end
self[1] = HorizontalGroup:new{
HorizontalSpan:new{ width = 5 },
FrameContainer:new{
padding = 0,
bordersize = self.bordersize,
dimen = {
w = self.width,
h = self.height,
},
CenterContainer:new{
dimen = {
w = self.width,
h = self.height,
},
TextWidget:new{
text = self.key,
face = Font:getFace("scfont", 22)
},
},
},
HorizontalSpan:new{ width = 5 },
}
end
--[[
Widget that displays an item for menu
]]
MenuItem = WidgetContainer:new{
text = nil,
detail = nil,
face = Font:getFace("cfont", 22),
width = nil,
height = nil,
shortcut = nil,
}
function MenuItem:init()
local shortcut_icon_w = 0
local shortcut_icon_h = 0
if self.shortcut then
shortcut_icon_w = math.floor(self.height*4/5)
shortcut_icon_h = shortcut_icon_w
end
self.detail = self.text
w = sizeUtf8Text(0, self.width, self.face, self.text, true).x
if w >= self.width - shortcut_icon_w then
indicator = " >>"
indicator_w = sizeUtf8Text(0, self.width, self.face, indicator, true).x
self.text = getSubTextByWidth(self.text, self.face,
self.width - shortcut_icon_w - indicator_w - 4, true) .. indicator
end
self[1] = HorizontalGroup:new{
ItemShortCutIcon:new{
width = shortcut_icon_w,
height = shortcut_icon_h,
key = self.shortcut,
},
HorizontalSpan:new{ width = 5 },
UnderlineContainer:new{
dimen = {
w = self.width - 5 - shortcut_icon_w,
h = self.height
},
HorizontalGroup:new {
align = "center",
TextWidget:new{
text = self.text,
face = self.face,
},
},
},
}
end
function MenuItem:onFocus()
self[1][3].color = 10
return true
end
function MenuItem:onUnfocus()
self[1][3].color = 0
return true
end
function MenuItem:onShowDetail()
UIManager:show(InfoMessage:new{
text=self.detail,
})
return true
end
--[[
Widget that displays menu
]]
Menu = FocusManager:new{
-- face for displaying item contents
cface = Font:getFace("cfont", 22),
-- face for menu title
tface = Font:getFace("tfont", 25),
-- face for paging info display
fface = Font:getFace("ffont", 16),
-- font for item shortcut
sface = Font:getFace("scfont", 20),
title = "No Title",
height = 500,
width = 500,
item_table = {},
items = 0,
item_shortcuts = {
"Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P",
"A", "S", "D", "F", "G", "H", "J", "K", "L", "Del",
"Z", "X", "C", "V", "B", "N", "M", ".", "Sym", "Enter",
},
is_enable_shortcut = true,
item_height = 36,
page = 1,
current = 1,
oldcurrent = 0,
selected_item = nil,
}
function Menu:init()
self.items = #self.item_table
self.perpage = math.floor(self.height / self.item_height)
self.page = 1
self.page_num = math.ceil(self.items / self.perpage)
self.key_events.Close = { {"Back"}, doc = "close menu" }
self.key_events.Select = { {"Press"}, doc = "chose selected item" }
self.key_events.NextPage = {
{Input.group.PgFwd}, doc = "goto next page of the menu"
}
self.key_events.PrevPage = {
{Input.group.PgBack}, doc = "goto previous page of the menu"
}
self.key_events.FocusRight = nil
self.key_events.ShowItemDetail = { {"Right"}, doc = "show item detail" }
if self.is_enable_shortcut then
self.key_events.SelectByShortCut = { {self.item_shortcuts} }
end
self[1] = CenterContainer:new{
dimen = {w = G_width, h = G_height},
FrameContainer:new{
background = 0,
radius = math.floor(self.width/20),
VerticalGroup:new{
TextWidget:new{
text = self.title,
face = self.tface,
},
-- group for items
VerticalGroup:new{
},
TextWidget:new{
text = "page "..self.page.."/"..self.page_num,
face = self.fface,
},
VerticalSpan:new{ width = 5 },
}, -- VerticalGroup
}, -- FrameContainer
} -- CenterContainer
self:_updateItems()
end
function Menu:_updateItems()
self.layout = {}
self[1][1][1][2] = VerticalGroup:new{}
local item_group = self[1][1][1][2]
for c = 1, self.perpage do
local i = (self.page - 1) * self.perpage + c
if i <= self.items then
local item_shortcut = nil
if self.is_enable_shortcut then
item_shortcut = self.item_shortcuts[c]
if item_shortcut == "Enter" then
item_shortcut = "Ent"
end
end
item_tmp = MenuItem:new{
text = self.item_table[i].text,
face = self.cface,
width = self.width - 14,
height = self.item_height,
shortcut = item_shortcut
}
table.insert(item_group, item_tmp)
table.insert(self.layout, {item_tmp})
--self.last_shortcut = c
end -- if i <= self.items
end -- for c=1, self.perpage
-- set focus to first menu item
item_group[1]:onFocus()
end
function Menu:onSelectByShortCut(_, keyevent)
for k,v in ipairs(self.item_shortcuts) do
if v == keyevent.key then
local item = self.item_table[k]
self.item_table = nil
UIManager:close(self)
debug(item)
-- send events
break
end
end
end
function Menu:onNextPage()
if self.page < self.page_num then
local page_info = self[1][1][1][3]
self.page = self.page + 1
self:_updateItems()
self.selected = { x = 1, y = 1 }
self[1][1][1][3] = TextWidget:new{
text = "page "..self.page.."/"..self.page_num,
face = self.fface,
},
UIManager:setDirty(self)
end
return true
end
function Menu:onPrevPage()
if self.page > 1 then
local page_info = self[1][1][1][3]
self.page = self.page - 1
self:_updateItems()
self.selected = { x = 1, y = 1 }
self[1][1][1][3] = TextWidget:new{
text = "page "..self.page.."/"..self.page_num,
face = self.fface,
},
UIManager:setDirty(self)
end
return true
end
function Menu:onShowItemDetail()
return self.layout[self.selected.y][self.selected.x]:handleEvent(
Event:new("ShowDetail")
)
end
function Menu:onClose()
UIManager:close(self)
return true
end

@ -44,6 +44,30 @@ function clearGlyphCache()
glyphcache = {}
end
function getSubTextByWidth(text, face, width, kerning)
local pen_x = 0
local prevcharcode = 0
local char_list = {}
for uchar in string.gfind(text, "([%z\1-\127\194-\244][\128-\191]*)") do
if pen_x < width then
local charcode = util.utf8charcode(uchar)
local glyph = getGlyph(face, charcode)
if kerning and prevcharcode then
local kern = face.ftface:getKerning(prevcharcode, charcode)
pen_x = pen_x + kern
end
pen_x = pen_x + glyph.ax
if pen_x <= width then
prevcharcode = charcode
table.insert(char_list, uchar)
else
break
end
end
end
return table.concat(char_list)
end
function sizeUtf8Text(x, width, face, text, kerning)
if text == nil then
debug("sizeUtf8Text called without text");

@ -85,8 +85,8 @@ end
Containers will pass events to children or react on them themselves
]]
function WidgetContainer:handleEvent(event)
-- call our own standard event handler
if not self:propagateEvent(event) then
-- call our own standard event handler
return Widget.handleEvent(self, event)
else
return true
@ -168,9 +168,9 @@ TextWidget = Widget:new{
}
function TextWidget:_render()
local h = self.face.size * 1.5
local h = self.face.size * 1.3
self._bb = Blitbuffer.new(self._maxlength, h)
self._length = renderUtf8Text(self._bb, 0, h*.7, self.face, self.text, self.color)
self._length = renderUtf8Text(self._bb, 0, h*0.8, self.face, self.text, self.color)
end
function TextWidget:getSize()
@ -261,7 +261,7 @@ function TextBoxWidget:_render()
for _,l in ipairs(v_list) do
pen_x = 0
for _,w in ipairs(l) do
renderUtf8Text(self._bb, pen_x, y, self.face, w.word, true)
renderUtf8Text(self._bb, pen_x, y*0.8, self.face, w.word, true)
pen_x = pen_x + w.width + space_w
end
y = y + line_height_px + font_height
@ -459,13 +459,17 @@ UnderlineContainer = WidgetContainer:new{
function UnderlineContainer:getSize()
local contentSize = self[1]:getSize()
if self.dimen then
if contentSize.w < self.dimen.w then contentSize.w = self.dimen.w end
if contentSize.h < self.dimen.h then contentSize.h = self.dimen.h end
end
return { w = contentSize.w, h = contentSize.h + self.linesize + self.padding }
end
function UnderlineContainer:paintTo(bb, x, y)
local contentSize = self[1]:getSize()
local contentSize = self:getSize()
self[1]:paintTo(bb, x, y)
bb:paintRect(x, y + contentSize.h + self.padding,
bb:paintRect(x, y + contentSize.h - self.linesize,
contentSize.w, self.linesize, self.color)
end

@ -71,15 +71,42 @@ function Clock:getTextWidget()
}
end
quiz = ConfirmBox:new{
Quiz = ConfirmBox:new{
text = "Tell me the truth, isn't it COOL?!",
width = 300,
ok_text = "Yes, of course.",
cancel_text = "No, it's ugly.",
cancel_callback = function()
UIManager:show(InfoMessage:new{
text="You liar!",
})
end,
}
menu_items = {
{text = "item1"},
{text = "item2"},
{text = "This is a very very log item whose length should exceed the width of the menu."},
{text = "item3"},
{text = "item4"},
{text = "item5"},
{text = "item6"},
{text = "item7"},
{text = "item8"},
{text = "item9"},
{text = "item10"},
{text = "item11"},
{text = "item12"},
}
M = Menu:new{
title = "Test Menu",
item_table = menu_items,
width = 500,
height = 400,
}
quiz:init()
UIManager:show(Background:new())
UIManager:show(Clock:new())
UIManager:show(quiz)
UIManager:show(M)
UIManager:show(Quiz)
UIManager:run()

Loading…
Cancel
Save