Comments

Log in with itch.io to leave a comment.

Hi, I am having issues with the .setCallback function. I am trying to have it change variables in my objects or set different callbacks dynamically in a for loop, but I believe I am having variable scoping problems. If you know of any way to work around this or need me to share more details, please let me know.

Otherwise, everything else is working great, thank you for this great asset.

Hi and thanks for using my library. Glad it's being useful.

It would be very helpful to check out your examples in more detail to understand what you are trying to do, but I'd anticipate most cases are totally doable.

The scope for setCallback is object where the panel and widget is defined. For example, the following code, in the Create event of the obj_Player object, will rotate said object's sprite when held:


If the panel is created in another object, and there's only one instance, you can refer to the calling object and/or instance directly:


If you want to do something slightly more complex, you can bind the function to a specific instance via a method. For example, if there are three obj_Player instances, you can dynamically create three buttons in a panel, each of which rotates a specific obj_Player instance:



For the last example, I have attached a very small project here.

Please, share your code and or detail your use cases and I will happily guide you.

(1 edit)

Thank you for the reply. I just cleaned up the main section of code I am having problems with and tried implementing what you sent, but I still can't get it to work. The code above works, but only because of the hard-coded fix I put after the for loop. 

I apologize if my code is hard to read because I am entirely self-taught and don't know any standard variable conventions. I want to use a loop so I can dynamically add new buttons. 

The ".setImageAlpha" sections are only there for testing purposes so I can see results faster, so my main concern is the array updating portion. This basically just changes a variable that holds information on what is equipped to the player. I am trying to set up a system that will allow me to add more options quickly in the future while modifying as little code as possible. If this isn't enough for you to help me, I can share more of the project, but fair warning, my code is very cluttered right now.

there was one other thing I was trying to do that is less important, but I thought I would still bring it up. I first ran into troubles when I tried setting up the .setCallback in a script so I could reduce the size of my code, but I had similar issues to the above problem where the function couldn't find the variable I wanted to access. my current hard-coded solution is sufficient for my project so no worries if we can't figure this one out.

The problem you have is indeed with variable scoping, not gooey. The basic idea is that local variables are not passed to functions/methods in the scope automatically, like in other programming languages (this automatic behavior, which is not present in GML right now, is called "closure"). So in order to be able to access those variables from inside those functions/methods, you need to "bind" the method to a struct which contains the variables you need, using the `method()` call (this is what I did in the example above). 

More info about the method function and its uses in the manual.

In your example, I'm not really understanding what `obj_cybterm` is (I think you have a terminal which the player can access and you are displaying one button per each upgrade the player can choose for its left and right robotic arm, or something), but the first issue I see is that, even though you are using `method()` to bind the `_id` variable (which holds the reference to the specific `obj_cybterm` object you found with the `instance_find` function), then on the callback code you are not referencing that variable. Also, you are using the local variable `_i` inside the function, which has not been declared in the struct.

Without seeing the project I cannot recommend the exact code to use, but I'm sure this is the issue. If you are willing to share your project I will happily review and let you know what options you have. The other option is I can try to quickly whip up a project with the functionality I described so you can take it from there.

Finally for the second part you can of course use a script, but again, you'll have to be careful to bind it to the appropriate instance in order to reference its variables correctly.

I have created a small sample project here. Let me know.

Thank you. This is exactly what I needed. I have never used 'method()'  before, so your code helped me realize what I was missing. This also allowed me to set that script up properly. I'll be sure to share the game when it's in a more functional state. 

Hi, I am on 2024.6.1 but it didn't work at first.
I had to put the "UI" object manually in the first room and delete the lines

// Check if UI object exists, if not create it
if (!instance_exists(UI)) {
   var _id = room_instance_add(room_first, -1, -1, UI);
}

when I didn't delete those lines, I had two "UI" objects, one had not variables/functions at all in it. And that one was trying to be referenced by other objects.

I am not shure, but those lines are in a script, when this gets executed, is it possible that there are instances already created? I think they are executed before any instances are created, so checking if an instances exists makes no sense?

Hi and thanks for using the library.

What gooey version are you on? I reckon 2024.6, over Gamemaker's 2024.6.1, right?

In any case, it seems there is indeed a bug when you try to use a UI widget in the same frame as creating the gooey object automatically. Given there's been an Scribble update just today, I've gone ahead and released 2024.7, which should fix the above. Can you please try and let me know if it works?

Thanks

(5 edits)

Thanks for your reply,

yes I was on gooey 2024.6 / Gamemaker 2024.6.1, just downloaded gooey for the first time the other day. I was trying out some other libraries before and gooey was the first one that (almost) worked without bugs on the first try and was the only one I could understand good enough to fix things myself. So thanks for making gooey :)

I tried gooey 2024.7 and now it works out of the box, thanks.

When I built my first UI a ran into some minor problems:
I made a panel, added a grid and added buttons +extra sprites on the left and UIText on the right column. When I try to make the text left-aligned it looks like this:

It places the text on the left side on the cell, but the text itself is centered.
So I wanted to change the _text_format of the UIText to "[fa_left][fa_middle]", but UIText has no _text_format property and no setTextFormat method. As a workaround I can set it back to UI_RELATIVE_TO.MIDDLE_CENTER, or is there another possibility/approach I don't see?

So my current wishes for gooeys future are:
- "setTextFormat" method for every element that has text
- extra "secondary" sprite for buttons (for icons instead of text on buttons independend of the button sprite itself)
- "setScaleMouseover", "setScaleClick"... for buttons
[EDIT] - window_set_cursor does not work reliable, so for now an option to disable it would be nice  found the configurations
- The YT video is great but a example project would be great for starting out

Of course I can try to implement it myself, but that would only make sense if I would use your repo and I am not very experienced with GIT...

Hi and thanks!

Not entirely sure of what are you trying to do with UIText. However, I *think* you are trying to create a button that has an icon and text on it, right?

If so, you can easily do this with the UIButton and leveraging Scribble's inline images:

on mouseover:


However, in case you *do* want to use UIText for other uses (for example, for creating a text label to display the price of the upgrade, on the right grid cells) you can use it:

Indeed, the UIText does *not* currently have a .setTextFormat() method (I will consider adding it or at least mentioning it in the docu, however the text string itself can be formatted with any Scribble tag. For example:

Note also that this formatting is independent of the position of the UIText within the grid cell, which you can control using the relative_to argument when creating the UIText element.


Here's a sample project with all the code.

Hope it helps, let me know,

Thank you very much, this helped me a lot.
Yes you are right, I wanted Button with a sprite and text, I didn't think about scribbles inline sprites, that was exactly the hint I needed. Now it looks like I wanted it:

Now I can continiue prototyping before I begin to tackle the next UI challenges like scrolling and Tooltips.
I already took a look at your scrolling example you posted in the comments, I am excited to see if I can make a working scrollbar, too.

Glad to know! That game prototype is looking sick!

Hi, the UITextBox doesn't work for me. The caret is always shown in the top left corner of the sprite, also the text . I'm using the latest GM and gooey version 2024.1. I was able to position place holder text (which should be "Hello world" in the screenshot) with fa_left to make it readable, the caret still appears at the top left corner and the input behaves like it's fa_center'ed.

Am I'm doing something wrong? I tried to find a solution in the docs, but wasn't successfull.

(1 edit)

Hi and thanks for using the library! Hope it's useful.

You can use the .setTextFormat() method to fix it:


var _textbox = new UITextBox("Test_Textbox", 80, 30, 150, 50, grey_button08); 
_textbox.setTextFormat("[fa_left][fa_top][c_black]").setPlaceholderText("Hello World"); 
_panel.add(_textbox);

Full code for example above:

var _panel = new UIPanel("Test", 40, 40, 300, 400, yellow_panel); 
_panel.setTitleFormat("[fa_center][fa_top][c_black]").setTitle("NEW GAME"); 
var _label = new  UIText("Test_SeedText", 30, 30, "[fa_left][fa_top][c_black]Seed: ");
_panel.add(_label);
var _textbox = new UITextBox("Test_Textbox", 80, 30, 150, 50, grey_button08);
_textbox.setTextFormat("[fa_left][fa_top][c_black]").setPlaceholderText("Hello World");
_panel.add(_textbox);
var _button = new UIButton("Test_Button", 0, -20, 280, 40, "Start game", yellow_button00, UI_RELATIVE_TO.BOTTOM_CENTER);
_button.setCallback(UI_EVENT.LEFT_RELEASE, function() {     show_message(UI.get("Test_Textbox").getText()); });
_panel.add(_button);


Let me know if there's anything else I can help with!

Ah, I forgot fa_top! Thanks a lot! Now it works fine. 

It's a wonderful library, thanks for making it. :) 

(-1)

Are there downloadable docs or just online?

Hey, I apologize for the delay. Currently, documentation in HTML format is only available online. However, HTML documentation is generated automatically from the JSDoc comments on the Gamemaker script itself (above each function/method), using another tool I wrote named GMLDocMaker. So, this means that all documentation is essentially inside the gooey script. You can use the find functionality (or middle click a function name in Gamemaker) and it will show you the explanation.

If you still need the offline documentation I could try to generate an offline version in a format like PDF or so. It won't be pretty, but it might work.

Let me know if I can further help!

Thanks for the reply manta ray! I will look into the GMLDocMaker that you wrote. 

Is it possible to make the items in the grid scrollable from within the panel? I.e. level select buttons? Seems like the buttons I'm making are getting compressed to the panel size.

(1 edit)

Hi, hope you're fine!

I have published a 2024.1 version which (hopefully) fixes the scroll bug.  I also updated the online documentation and generated an offline version of the HTML documentations (you can download it as well).

With this version, using a somewhat "creative" approach, you'll be able to create a scrollable grid like so:


Test code is as follows:

if (!UI.exists("LevelSelectPanel")) {     var _num_levels = 30;     var _columns = 3;          var _panel = new UIPanel("LevelSelectPanel", 500, 200, 500, 500, blue_panel, UI_RELATIVE_TO.MIDDLE_CENTER);     _panel.setTitle("Level Select").setTitleAnchor(UI_RELATIVE_TO.MIDDLE_CENTER);          var _container = new UIGrid("ContainerGrid", 2, 1);     _container.setRowProportions([0.2, 0.8]);     _container.setShowGridOverlay(true);     _container.getCell(1,0).setClipsContent(true);          var _cnt = _container.addToCell(new UIGroup("GridContainer", 0, 0, 500, 1500, red_panel), 1, 0);          var _grid = new UIGrid("LevelsGrid", _num_levels div _columns, _columns);     _grid.setSpacingHorizontal(20).setSpacingVertical(20).setMarginLeft(50).setMarginRight(50).setMarginTop(10).setMarginBottom(10);               for (var _level = 0; _level < _num_levels; _level++) {         var _button = new UIButton("Level"+string(_level+1), 0, 0, 0, 0 , "Level "+string(_level+1), blue_button00, UI_RELATIVE_TO.MIDDLE_CENTER);         _button.setInheritWidth(true).setInheritHeight(true).setCallback(UI_EVENT.LEFT_RELEASE, method({level: _level}, function() {             show_message("You selected level "+string(level+1));         }));         _grid.addToCell(_button, _level div _columns, _level % _columns);     }     _container.addToCell(_cnt, 1, 0);     _cnt.add(_grid);     _panel.add(_container); }  if (keyboard_check(vk_down))    UI.get("ContainerGrid").getCell(1,0).scroll(UI_ORIENTATION.VERTICAL, -1, 5); if (keyboard_check(vk_up))        UI.get("ContainerGrid").getCell(1,0).scroll(UI_ORIENTATION.VERTICAL, 1, 5);

Hope you find it useful!


Thank you for the quick reply, fix, and demo! I'm having a hard time trying it out because the buttons get scaled strangely (I've had this happen a few times now when dragging the panel)

Can you send me your project or object code?

Sharing another snippet of something I had to kinda of workaround.

I have a couple UIPanel widgets that I add as children to a grid. Upon closing the room I call a function to remove all widgets that are 'bound' to the room. Sadly panels that are parented to a Grid don't fully delete themselves. I had to use this workaround to get them to completely delete:

if (_widget.getType() == UI_TYPE.PANEL) {
    _widget.__parent.remove(_widget.getID());
    UI.__destroy_widget(_widget);
}
_widget.destroy()


Full snippet for the logic to register and later remove widgets when the room ends:

global.widgets_to_remove = []
// Registers a widget that will be removed when the room ends
function widget_bound_to_room(_widget)
{
    array_push(global.widgets_to_remove, _widget)    
    return _widget
}
// Called on room end to remove bound widgets
function widgets_remove_room_bound()
{
    for (var _i = array_length(global.widgets_to_remove) - 1; _i >= 0; _i--) {
        var _widget = array_pop(global.widgets_to_remove)
        
        custom_event_call("widget_removing_room_bound", {
            widget_to_remove: _widget    
        });
        
        // Workaround for panels not removing correctly
        if (_widget.getType() == UI_TYPE.PANEL) {
            _widget.__parent.remove(_widget.getID());
            UI.__destroy_widget(_widget);
        }
        
        _widget.destroy()
    }
}


To use it:

1. When creating widgets call widget_bound_to_room on it, e.g:

var _crafting_group = widget_bound_to_room(new UIGroup("CraftingGroup", 0, 0, 250, 0, spr_back, UI_RELATIVE_TO.MIDDLE_CENTER))
_crafting_group.setInheritHeight(true)
_crafting_group.add(widget_bound_to_room(new UIPanel("ParentedPanel", _x, _y, _width, _height, spr_frame_simple)))


2. When the room ends call:

widgets_remove_room_bound();
(1 edit)

Hi again, 

UIPanels are not meant to be nested (at least I didn't design it that way!), so I'm interested in your use case for that and how are you implementing it. I can see you would have problems destroying them, but there might be other things that don't work as you think, just because again, when I thought about UIPanels I always conceived them as top-level widgets.

It would be really useful if you could share your code and/or images to see how you are using them nested. 

Best,

manta ray

(2 edits)

Heya again,

Thanks for explaining that the UIPanels weren't meant for that. I used them to create panels with a background sprite, but now that you said that I was doing something unintended- I double-checked the docs and found that a UIGroup can have a background sprite as well.

I guess the term 'panel' gave me the illusion that they would be similar to WinForms Panels, but they're more akin to Forms there I guess. I've switched to UIGroups for my purposes, but will leave the code snippet up since it may be useful to someone else for other reasons.

Thanks again for your quick support!

Thanks so much for sharing this awesome UI framework for free. Saves me a ton of work and it functions intuitively and is quite stable.

One thing I want to share is that it seems UIGrid.scroll doesn't move the children in cells. The cell groups themselves move (I can see that with setShowGridOverlay), but the children stay where they are initially placed.


For others struggling with this: I've made this (temporary) workaround that hotfixes the problem. Call it on the grid you want to scroll with the same parameters you would give to the .scroll method:

function ui_grid_scroll(_ui_grid, _orientation = UI_ORIENTATION.HORIZONTAL, _sign = 1, _amount = UI_SCROLL_SPEED)
{
    // Just this scrolls the cell groups, but their children aren't updated. BUG?
    _ui_grid.scroll(_orientation, _sign, _amount)
    
    // HOTFIX that triggers the children to update to their correct position
    var _children = _ui_grid.getChildren()
    
    for (var _i = 0; _i < array_length(_children); _i++) {
        var _child = _children[_i]
        
        _child.scroll(_orientation, _sign, 0)
    }    
}

Thanks so much for the compliments, I'm glad to hear it's being useful!

I will check this and fix it if necessary, as soon as I can. One question, are your child elements in the grid cells UIPanels (as commented in the other question above)?

Heya :)

No the UIGrid did not contain any UIPanels, however the structure was somewhat complex:

  • UIPanel
    • UIGrid (2 rows, 1 column)
      • UIGrid in 1st row (1 row, 3 columns - column definitions [1, 1, 1])
        • UIButton (column 1)
        • UIButton (column 2)
        • UIButton (column 3)

Sadly I can't share a minimal, reproducible example atm since a lot of the code is intertwined with custom functions and little time to extract it.

(+1)

Hi, just to let you know, I just published 2024.1 version which hopefully fixes the scrolling bug.

Hey, it looks like the documentation site is down. Any chance you could get it back up? Thank you!

Hi @arronmarc, apologies for this problem. It should be fixed by now, it had an invalid redirect rule that was causing the problem. Thank you for your patience!

Amazing, thank you so much!

hi, was just trying to find a simple method for returning co-ords for anything a panel, widget etc. Found my way through browsing functions to work out that __dimensions works fine, just checking is the docs suppose to say __dimensions instead of __UIDimensions?

There's a getDimensions() method for all widgets (since they all inherit from the UIWidget struct). Accessing with __dimensions is also ok but not preferred (you should access with the given getters/setters).

question: So I'm creating an upgrade button and i want a button sprite but also the sprite of the object ontop.

I did something like this:
vehicle_upgrade_image = vehicle_upgrade.add(new UISprite("VehicleUpgradeImage", 0, -8, _sprite, , , , UI_RELATIVE_TO.MIDDLE_CENTER));

works great.. However i cant click on the button while mousing over the sprite.

What's the most optimal way of doing this, I may investigate the UIGroup widget but just wondering if there is a hidden method that is like click-through but for other ui components

(1 edit)

Hi, there's currently no click-through method for elements. What I'm doing to circumvent this in my games is I'm setting the LEFT_RELEASE callback of the sprite and calling the button callback:


with (_panel.add(new UISprite("YourSprite", _x, _y, _w, _h, _spr, 0))) {
    setCallback(UI_EVENT.LEFT_RELEASE, function() {
        var _f = UI.get("YourButton").getCallback(UI_EVENT.LEFT_RELEASE);
        _f();
    });
}

yeah this is what i ended up doing https://ldjam.com/events/ludum-dare/53/clickexpress you can see some ui stuff in action here

Cool! Haven't been able to check it out (I'm at work) but I followed you on the site so I remember later. I also made an LD game for this edition and used gooey:


https://ldjam.com/events/ludum-dare/53/medieval-messenger

also sorry for spamming ur itch comments HAHAH, much love for the support this library is awesome

No problem! Happy gamemaking

so turns out i was dumb and i figured it out on stream!

-- Question? Rows should go horizontally no? This is how i know them from spreadsheets.. However idk if its a bug or if you set it up this way. Rows go vertically and collums at the moment go horizontally.

If you could clarify if this is intentional that would be great :)

slowly making progress figuring it out thanks for the hard work and speedy replies <3

that being said it's not really a big issue i can invert it.

Followed your example code and i am getting there!! Thank you for this library it is awesome


Great that you managed to get it working on your own!

The same as with all spreadsheets (and most programming languages), rows indeed "go vertically" (this means they increment as you go down the grid) and columns "go horizontally" (this means they increment as you go from left to right). So if you have a 4x3 grid, it looks like this:


row=0, col=0row=0, col=1row=0, col=2
row=1, col=0row=1, col=1row=1, col=2
row=2, col=0row=2, col=1row=2, col=2
row=3, col=0row=3, col=1row=3, col=2


So if you need to add a widget to the bottom left cell, you'd say

_grid.addToCell(_widget, 3, 0);

This is the same as it happens on spreadsheets (the only difference being that rows and columns on spreadsheets start with 1 not with 0).


Also share your stream video if you can!


Best,

José

https://www.twitch.tv/videos/1790632218 here is the stream VOD was fun to bring it together based on your example code you wrote. Obviously you can see i have some issues still, my GUi rescaling makes things a bit tricky with text, I'm still having a few issues around nice ways of updating the UI when picking up items. Is there a way to not have to redraw the UI when updating for example my ds_grid?

Hi, not sure if I understand correctly. The way to update a widget once it's created is to either set a binding to a variable or method (if simple, i.e. the value of a UIProgressbar or the text of a UIText) or use setPreRenderCallback/setPostRenderCallback. Once you set it up, it's automatic.

When you say "when picking up things" I'm imagining you are not pausing the game while the inventory is displayed, and you want the inventory to update when picking up a new item. In this case, you can set the redraw call when picking up the object. Make a parent object with that logic and you can inherit all your items from that object, so all of them trigger the redraw.

Let me know if I understood correctly or not, thanks. By the way, nice graphics in your project!

yeah,i was asking if there is a way to avoid having to trigger a redraw, I did get it working how I want it but I'm just wondering if recalling the "show_inventory" function is going to cause performance issues in the long run. If it's not really going to cause to many issues or be non-performant that's all good

___________________________________________

############################################################################################

ERROR in

action number 1

of Draw Event

for object object_ui:

Unable to find instance for object index -4

 at gml_Script_anon_UIGrid_gml_GlobalScript_scr_gooey_Widgets_225168_UIGrid_gml_GlobalScript_scr_gooey_Widgets (line 4398) -                                                  _widget.setDimensions(_x, _y, _w, _h);

############################################################################################

gml_Script_anon_UIGrid_gml_GlobalScript_scr_gooey_Widgets_225168_UIGrid_gml_GlobalScript_scr_gooey_Widgets (line 4398)

gml_Script_anon___UIWidget_gml_GlobalScript_scr_gooey_Widgets_278126___UIWidget_gml_GlobalScript_scr_gooey_Widgets (line 5319) -                                           _id.__updateGridDimensions();

gml_Script_anon_gml_Object_object_ui_Create_0_124_gml_Object_object_ui_Create_0 (line 11) -        var _grid_meta = _panel.add(new UIGrid("MetaGrid", 2, 1));

gml_Object_object_ui_Draw_0 (line 54) -               self.draw_inventory();       

___________________________________________

I randomly get this bug around grid usage by the way. I'm sure it's because I haven't implimented them correctly but thought you should know.


// Create grid with two rows, one column and 80%-20% proportions (upper part will be the inventory and lower part the description)

var _grid_meta = _panel.add(new UIGrid("MetaGrid", 2, 1));

_grid_meta.setRowProportions([0.8,0.2]).setMarginTop(_panel.getDragBarHeight());


-- This is what I wrote around grids

I think this is due to the grid width not being the same as the height!

When it's the same there is no issues hmmnn

Kindly share your full code in pastebin or similar (not pasted here in the comments) or share your GM project, so I can help debug it.

One possible cause that will bring a similar error with UIGrids is you're trying to add a widget to a non-existent grid cell. The addToCell(_row, _col) method needs the row specified first and then the column.

it would be really awesome if there was more info or tutorials on using the library. Do you plan to make a few more videos?

For example I'm thinking how to use it to build a inventory, I'm playing around with the UIGrid but yeah I think if there was a tutorial that went over how widgets link up more or what they are used for will help.

I appriciate the docs and the current video that is up.

Hi @NataeGames, 

I created a tiny demo game with a basic inventory for you!

You can play with it at https://biyectivo.com/Inventory/

You can also download the full source code at https://bitbucket.org/biyectivo/inventory/src/main/. I tried to comment the key parts so it's faster for you to understand it.

Hope you like it!

wow I really appriciate that! I'll have a browse and get a grasp of how it was made thank you!

oh side note https://biyectivo.com/gooey/doc_scr_UI_Widgets.gml.html#UIButton the docs are bugged you cant view the whole page as the sidebar cuts it off :c

Thanks for the heads up, can you share your browser, browser version and OS please?

Windows 11 -- operaGX.
I zoomed out to 80% and i can see it thankfully

YO, amazing work. I praise this so hard, im going to implement it into my game as

Odd Nite(wurmhole) said, I'm just getting into UI for my project and i was just browsing for any libraries to reference but this has allot of great infostructure.

I appreciate the hard work with this library thank you so much for your efforts 

Great, hope you find it useful!

You are a Saint. This comes right as I’ve started work on the UI of my project! 

hopefully it's useful. Let me know :)