airstruck / luigi Goto Github PK
View Code? Open in Web Editor NEWLovely User Interfaces for Game Inventors
License: MIT License
Lovely User Interfaces for Game Inventors
License: MIT License
Hello,
Is it planned to have a kind of table/grid widget with luigi ?
Something like :
Is someone already tried to do that ?
Regards,
Hello airstruck,
I'm new to LÖVE2d and testing various GUIs, among them is LUIGI. It works OK for my needs, except I can't get it to respond to keypress.
I built a simple layout with 4 buttons as the only active controls, it also has two panels to hold the buttons, and a status bar. I declared the "key" attribute on the buttons, but they never respond when I press the corresponding keys.
I suspect this is an issue with intercepting the keypressed and keyreleased events, but I can't get a clue on the example. Also, there is a "Backend" object in the example, that is not documented, and whose role is unclear. I'm searching also in that direction, but to no avail for now.
Thanks in advance for any answer and documentation update on the topic.
Benoît 'Mutos' Robin
Context menus created with the context
attribute work by adding a menu
child to a widget. This causes problems that need to be worked around elsewhere; for example stepper
looks for context menu children and gives them special treatment. Context menus should be handled without modifying the widget's children.
...and get rid of magic numbers. Maybe use same values as SDL?
I have a panel that I'm using for a a dialog box, but I seem to be unable to get the text component of it to update correctly.
Here's the panel I create:
local dialogOpts = {
type = 'panel',
text = 'Node information dialog box\nShould have a line break in it, but who knows?',
width = 350,
height = 150,
wrap = true,
background = {200, 200, 200, 240},
outline = {255, 255, 255, 255},
}
local panel = Layout(dialogOpts)
Once I've caled panel:show()
, however, I can't seem to update the text. Even if I call panel:hide()
, then change the text, and call show()
again.
Edit: To be more specific, I'm attempting to update the text as follows:
panel:hide()
panel.text = "new text"
panel:show()
Nothing major, just some additional polish.
Keyboard word selection:
Themes are doing too much work, they should be more accessible to designers. Move all function-attributes and some default attributes into engines. Expose most hard-coded values as engine parameters, with current values as defaults. Provide a default engine. Themes should be able to load the engine of their choice, or fall back to the default.
For example, if textWidget.value
is "foobar" and the user selects the whole thing (from left to right), then when textWidget.value
is set to "foo" (programatically, not by the user), the end of the selection range will extend past the end of the text. If the user hits the left arrow key at this point, an error is thrown.
Either the selection range should never be allowed to extend past EOT (clamp it in onChange), or it should be clamped to the text length when modifying it (clamp it in a bunch of internal functions).
context
attribute, containing some menu items. Default behavior for right mouse button would be showing the context menu.See love's textedited event, which is totally undocumented. The attached code is probably the most complete example of its usage that exists. SDL backend will be exactly the same, since love's functions don't do much of anything extra.
Compose events are used for some other cases that aren't CJK as well, but I think only CJK languages use candidate lists.
Love 0.9.2 doesn't actually include everything needed for proper IME support unless you FFI in l.k.setTextInput with additional arguments and update SDL.
(the unabridged version of the following code is here. You may want to look at draw(), and you'll want to ensure that start_editing is called every time the contents change)
-- 0.9 compat. Only *really* works if you've updated SDL, though.
-- function console.textedit(...)
-- return console.textedited(...)
-- end
-- CJK IME's need to know where the cursor is in the window and the size of the
-- text box in order to function properly.
--
-- All code tested with Mozc on Windows and Linux.
-- Pretend this is whatever code is needed to get the text cursor position in luigi instead of this console...
local function get_position()
local prefix = console.ps .. " "
local x = console.x + console.margin + console.font:getWidth(prefix)
local y = console.y + console.h + (console.lineHeight - console.fontSize) / 2 -1
local h = console.font:getHeight()
local text_l = utf8.sub(console.input, 1, console.cursor)
local text_r = utf8.sub(console.input, console.cursor+1, -1)
local pos = x + console.font:getWidth(text_l)
local w = console.w - x - 3
return pos, y, w, h
end
local function start_editing()
local x, y, w, h = get_position()
love.keyboard.setTextInput(console.visible, x, y, w, h)
love.keyboard.setKeyRepeat(true)
end
local function stop_editing()
console.editBuffer = nil
love.keyboard.setTextInput(false)
love.keyboard.setKeyRepeat(false)
end
-- alias so it's a little more clear why we're calling start() so much.
local update_ime = start_editing
-- You receive this event while a string is still being composed, so it's up to
-- you to display it properly as this happens.
-- "Properly" meaning you should draw a highlighted box with the contents of
-- editbuffer wherever the text cursor is (so you'll need to do some measuring
-- and temporarily insert characters into your display text)
function console.textedited(t, s, l)
if not console.visible then
return
end
if t == "" then
console.editBuffer = nil
else
console.editBuffer = { text = t, sel = s }
end
update_ime()
end
function console.focus(f)
if not console.visible then
return
end
if f then
-- Work around for Windows' stupidity.
stop_editing()
start_editing()
else
stop_editing()
end
end
-- Note: You only receive this event when the input has been finalized!
function console.textinput(t)
if t ~= console._KEY_TOGGLE and console.visible then
local text_l = utf8.sub(console.input, 1, console.cursor)
local text_r = utf8.sub(console.input, console.cursor+1, -1)
console.input = text_l .. t .. text_r
console.cursor = console.cursor + utf8.len(t)
update_ime()
return true
end
return false
end
For example, pressing 'tab' while two layouts are showing will focus the next focusable widget in each layout. Only the top layout should be affected.
Currently presses the focused widget (has different behavior in text widgets; it will probably change).
Maybe introduce a new attribute that tells a single button (per layout) to catch all 'enter' key presses. If present, pressing 'enter' presses that button, otherwise, it presses the focused widget (space bar always presses the focused widget).
Current document is hard to understand. It has no example and yet not complete. e.g. no style
field enum explanation
...and move handling out of renderer.
When typing a text longer than the edit box's width, the last character is displayed partially and the cursor disappears. The look is consistent with the control's boundary box being used for calculations rather than just the inner edit box, similarly to vrld/suit#27 (but I haven't looked at the code). [EDIT: Actually, it is more consistent with being always exactly 1 character behind. It is not a fixed width, as can be shown by entering series of MmMm and ilil]
There are other issues that I'm not sure if they are part of the same issue or not. When the input box is full, pressing the Home/End keys does not seem to make the new cursor position visible. It goes back to normal if the right cursor is pressed after the End key, or if the left cursor is pressed after the Home key.
For example, if another widget has a shortcut of 'z', pressing 'z' in the text widget should type a 'z' into the widget and not activate the other widget (current behavior as of latest commit). But, if another widget has a shortcut of 'escape' the text widget shouldn't trap this, since the text widget doesn't use that key.
In other words, keypresses not associated with text input should be allowed to propagate (unless the text widget has special handling for them, like 'ctrl-c').
From https://wiki.libsdl.org/CategoryKeyboard
SDL_Keycode values are mapped to the current layout of the keyboard and correlate to an SDL_Scancode. Values of this type are used to represent key symbols in the key.keysym.sym field of the SDL_Event structure, among other places. The values in the SDL_Keycode enumeration are based on Unicode values representing the unmodified character that would be generated by pressing the key, or the scancode value with the high bit set (bitwise ORed with 0x40000000) for those keys that do not generate characters. Keycode constants use the symbol name (lowercased for letters) prefixed with SDLK_ (eg: SDLK_SPACE).
Under the SDL backend, we should be able to test for that high bit and let the event propagate if it's present, or if any modifiers keys besides 'shift' were pressed. Not sure whether it's possible to test for that high bit under Love, or if a workaround exists.
'auto'
to 'shrink'
; shrinks to fit contents.'expand'
and treat it like false
, expands into available space.'shrink'
as default value for some widgets, like buttons.Happens rarely, but enough to cause trouble. Not sure why it happens, maybe an issue with SDL. Implementing #5 (first item) should fix it, probably.
If a widget has both text
and icon
, positioning everything properly is complicated. The Text
object is currently created by Painter
when rendering, but this causes problems when we need to get the text object before rendering (for example when determining a widget's "internal height"). If icon
didn't have to be taken into account when creating the Text
object, a Widget:getText
method would be much easier to manage.
The current system is nice because we can do this:
{ type = 'button', icon = 'save.png', text = 'Save' }
The new system could simply draw the text in front of the icon (so icon
and text
aren't really meant to be used on the same widget). Creating the same button might look like this now:
{ type = 'button',
{ icon = 'save.png' },
{ text = 'Save' }
}
Of course, button type widgets could do what menu items do, and create their own children based on their attributes (so the current syntax would still work). This adds complexity for individual widget types, but removes complexity from Widget
and Painter
.
Or, we can go the other direction, bite the bullet and move all the positioning stuff from Painter
into Widget
.
Another possibility would be changing the icon
and text
attributes to always create new children, and have dedicated types for those widgets. So the button could be written either way:
{ type = 'button', icon = 'save.png', text = 'Save' }
-- or
{ type = 'button', { image = 'save.png' }, 'Save' }
How do I destroy the UI correctly (e.g. when I switch to a different state)?
When I just use ui:hide()
the UI still seems to grab button press events etc. when I'm in a different state.
This problem happens exclusively with LÖVE 0.9.2. When hovering the mouse over the edit box, and inserting a space, the cursor jumps to the position where the mouse is.
It works fine both with LÖVE 0.10.0 and with luajit/SDL. I suspect it may have to do with the remapping of "space" to " " in the 0.9.0 -> 0.10.0 transition.
Key repeat in an input control does not work for some keys, notably for backspace and arrows.
It should probably be handled by preserving the user-set state of key repeat when focus goes elsewhere.
I want to implement my options dialog in my game with using luigi. Here is what I have:
local Layout = require("luigi.layout")
local Options = {}
Options.__index = Options
function Options.new(quit_callback)
local self = setmetatable({}, Options)
self.__quit = quit_callback
self.layout = Layout(require("layouts.options"))
return self
end
function Options:keypressed(key)
if key == "escape" then
self.layout:hide()
self:__quit()
end
end
function Options:draw()
self.layout:show()
end
return Options
And the layout.options
is the copy of example/layout/main.lua
file. Everything works fine (it shows) then I call "draw" of Options
object but I don't see any way to hide it. I want to be able to hide it by pressing escape
as you can see in the Options:keypressed
method.
P.S. If you are interested in my keypressed
, draw
methods - they are simply a delegates of love.keypressed
, love.draw
and other functions; I use custom stacked-view widget which passes it's top value to the love
and it's top object's functions are called.
Make Slices a drawable class; move slice handling out of renderer.
I can't enter the letter 'z' on the input box. When doing so, it presses a button instead and the input box loses focus.
Happens with both love2d and luajit+SDL.
This widget can be used as the root widget of a layout to manage properties of the window.
maximized
-> SDL_MaximizeWindow / SDL_RestoreWindowminimized
-> SDL_MinimizeWindow / SDL_RestoreWindowborderless
-> SDL_SetWindowBorderedfullscreen
-> SDL_SetWindowFullscreengrab
-> SDL_SetWindowGrab (will it work with Love?)icon
(override) -> SDL_SetWindowIconmaxwidth
/maxheight
-> SDL_SetWindowMaximumSizeminwidth
/minheight
(override) -> SDL_SetWindowMinimumSizetop
/left
(override) -> SDL_SetWindowPositionwidth
/height
(override) -> SDL_SetWindowSizetitle
-> SDL_SetWindowTitletext
widget uses print currently.I'm trying to figure out how to properly center child widgets within a layout? Currently I have three buttons, within a layout, the flow is set to x. I would like to 'middle center' those buttons within the full size of the layout (which is the window size).
I don't see any examples of this and it seems align only changes text and icons not widgets.
Here's a sample of the code:
local character_select = Layout {
id = 'characterSelect',
style = 'character_select_screen',
{
type = 'button',
id = 'btnWarrior',
text = 'Warrior',
width = 100,
height = 32,
style = 'chararcter_button'
},
{
type = 'button',
id = 'btnMage',
text = 'Mage',
width = 100,
height = 32,
style = 'chararcter_button'
},
{
type = 'button',
id = 'btnRanger',
text = 'Ranger',
width = 100,
height = 32,
style = 'chararcter_button'
}
};
local character_select_style = {
character_select_screen = {
flow = 'x',
},
chararcter_button = {
margin = 5,
align = 'center middle'
}
}
character_select:setStyle(character_select_style);
Steps to reproduce:
luajit: ./luigi/widget/text.lua:340: attempt to get length of local 'key' (a nil value)
stack traceback:
./luigi/widget/text.lua:340: in function 'isKeyTextInput'
./luigi/widget/text.lua:401: in function 'func'
./luigi/hooker.lua:79: in function 'callbacks'
./luigi/event.lua:16: in function 'emit'
./luigi/widget.lua:288: in function 'bubbleEvent'
./luigi/input.lua:25: in function 'func'
./luigi/hooker.lua:79: in function 'keypressed'
./luigi/backend/ffisdl.lua:89: in function 'run'
main.lua:108: in main chunk
[C]: at 0x55729b56e580
I noticed I had to uncomment the Backend.run()
line. I’m not sure if additional precautions should be taken when working with luigi and the SDL.
Currently only child widgets are considered when calculating the width/height of a widget's contents. Also consider text and icon.
The fix for issue #37 broke the tab key from a text widget for me.
I think that the problem is a confusion on what the return type and value of the event should be, because this fixed it for me:
diff --git a/luigi/widget/text.lua b/luigi/widget/text.lua
index 23813f1..5d3482c 100644
--- a/luigi/widget/text.lua
+++ b/luigi/widget/text.lua
@@ -381,9 +381,9 @@ This color is used to indicate the selected range of text.
local act = self.keyActions[event.key]
if act then
local result = act()
- if result then return true end
+ if result then return end
end
- return false
+ return true
end)
self:onDisplay(function (event)
By type I mean that Event:emit checks explicitly for nil:
if result ~= nil then return result end
Hello airfriend,
I think the body background are not set in
https://github.com/airstruck/luigi/blob/gh-pages/doc/ldoc.css
You should add background-color: white;
inside the body section ?
Scancodes are helpful in that they are independent from the user’s keyboard layout (and are not “unknown” when unicode characters are being entered…).
Löve’s API makes it easy to obtain them: https://love2d.org/wiki/love.keypressed
Haven’t checked SDL’s API, sorry. :(
Brainstorming ideas for making the shortcut
attribute make more sense across platforms.
Consider this example:
{ type = 'button', text = 'Save', shortcut = 'ctrl-s' }
This is fine on Windows/Linux, but Mac users will want command-s as the shortcut for saving things. Possible solution (this won't actually work yet; shortcuts don't recognize "gui" as a modifier key yet):
{ type = 'button', text = 'Save', shortcut = { 'ctrl-s', 'gui-s' } }
Now Mac users can press command-s, but they can also press ctrl-s, and Windows/Linux users can press win-s. Only the appropriate shortcut for the user's platform should work.
Another idea:
{ type = 'button', text = 'Save', shortcut = { 'ctrl-s', 'command-s' } }
The command-
modifier would only be relevant on Mac, and would never be triggered elsewhere. Similarly, option-
could be used for the alt key, but only on a Mac. Problem is, ctrl-s still works on Mac, but shouldn't; we'd need something to call the ctrl key that only applies to non-Mac.
And another idea:
{ type = 'button', text = 'Save', shortcut = 'c-s' }
Here, c-s
can mean command on Mac and ctrl elsewhere. This only solves a subset of the problem, but it's probably a large subset and it's a reasonably clean solution.
Current behavior is ctrl-
shortcuts really means either ctrl or gui key is pressed, regardless of platform. This should probably change.
Related: #25
Some attributes should cascade.
Definitely font
and size
, anything else?
Is it possible to assign default states to radio buttons? Let's say I want to create an options screen where the user can select a few things:
I'd store these settings in a file on the user's system and want to reload them next time the program is started. How would I load default states for the selected buttons?
I want to create at run time a panel with a variable list of buttons (or labels). I'm aware that I can scroll using the mouse wheel, but I want to do it using a slider. scrollBy function works, but I can't figure how to synchronize scrolling and slider position.
group
attribute only exists for radio
type widgets; support it everywhere (at least menu items and buttons should be toggle-able somehow).layout.myGroup.value
and layout.myGroup.onPress(...)
will work.I'd like to use LUIGI for my game, but it uses framework which has letterboxing, so it has these restrictions:
No call should be made to love.graphics.reset
and love.graphics.origin
. Additionally, graphics state must be balanced!
love.mousepressed
, love.mousereleased
, love.mousemoved
, love.<more handles>
shouldn't be overridden. It's substitute is available, and additionally for mouse/touch events, handles the coordinates because letterboxing.
Touch events and mouse events are same.
What's the better way for emulate a combobox? The only thing that occurs to me is to use a menu->menu.items to select an option, and change menu text accordingly.
It would be nice if Luigi would allow certain actions to be performed as long as a button is pressed (e.g.: Deleting characters while backspace is pressed, or moving the cursor when the arrow keys are pressed).
All in all it is looking pretty nice already 😊 I would love to implement it in some of my projects asap 👍
Attributes are in a static module right now, could either:
Widgets already have an attributes
property where some of the attribute values are stored, maybe name the new property attributeDescriptors
?
In general, shortcuts on OS X should use command key instead of control key.
Use love.system.getOS() == 'OS X'
in Love and SDL_GetPlatform() == 'Mac OS X'
in SDL to figure out if user is on a Mac.
Add a special function like Backend.isControlPressed
that detects command key on Mac and control key everywhere else. Is there a better name for this, some word that refers to either a command or control key?
Looks like scrolling doesn't work anymore. Tried it both in the example and my own project (I'm only tested my MBP's trackpad so maybe it's just mac-specific?).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.