Skip to content
This repository has been archived by the owner on Dec 2, 2019. It is now read-only.

Sample code not working? #2

Closed
ktb92677 opened this issue Jun 27, 2015 · 24 comments
Closed

Sample code not working? #2

ktb92677 opened this issue Jun 27, 2015 · 24 comments

Comments

@ktb92677
Copy link

Hey, I have many questions/comments about your sample code under the README. (this is all c++)

  1. Firstly it seems that the first line needs to be changed to this: struct gui_command_buffer *buffer = new gui_command_buffer; or else it doesn't work on this line:gui_foreach_command(cmd, buffer) {
  2. In reference to void *memory = malloc(MEMORY_SIZE); What is memory size? I noticed that in the demo it was set to 64 * 1024... what is the significance of this?
  3. In reference to len = gui_panel_edit(&layout, buffer, len, 256, &active, GUI_INPUT_DEFAULT); What is len? what is active?
  4. I have been trying for a very long time for your example to work but its always crashing on "gui_panel_begin" I have confirmed that the assert statements are returning properly, beyond that I didn't want to have to debug your code to see where it crashes. Do you think you could point me in the right direction here?
@ktb92677
Copy link
Author

As an extension onto #4 I have also tried implementing your OpenGL example (without the OpenGL because I'm using a framebuffer to implement this) and even in the demo.c the program crashes at " running = gui_panel_begin_stacked(&layout, &control->hook, stack, "Control", in);" in "update_control". Any assistance would be greatly appreciated!

@vurtun
Copy link
Owner

vurtun commented Jun 28, 2015

Thank you for your feedback.
I.) You are right the example shows gui_foreach_command(cmd, buffer), but it should actually be gui_foreach_command(cmd, &buffer) since it uses a pointer and needs the address of the buffer.

II.) There are three ways to allocate memory. Fixed size memory, user controlled growable fixed size memory and an allocator. The fixed size you describe is what I personally use the most since it is the easiest and most UIs have roughly known size.
So to not further complicate the memory allocation issue I just allocate more than enough memory. To really check how much memory is being used I sometimes check the gui_command_buffer and if needed upscale the memory size. For example the demo can run with 32 kbyte just fine and barely hits 16 kbyte in the worst case but I use 64 kbyte since I can be sure that it will never be reached with the given GUI. It is important to know that the worst case that could happen by using not enough memory is just that not every part of the GUI is being drawn which is easy to see and to fix.

If that is to much hassle you can create an gui_allocator and initialize the buffer with gui_command_buffer_init instead. This guarantees that you will always have enough memory but it requires a little bit more work.

III.) I updated the example code to hopefully make it more clear.

IV.) First of the GUI_ASSERT macro does not define anything by default, since the project does not use the the standart library by default I cannot use the normal assert function. So you have to

#define GUI_ASSERT(expr) assert(expr)
#include "gui.h"

before including the header file. Since it was not obvious I added the line to the demos and added a additional assert to the gui_panel_begin function. Please check again if the OpenGL demo still does not work or gives an assert, since it works for me which makes this quite complicated.

If the crash is still happening please report on the actual line in the gui_panel_begin function the program crashes on so that I can get a more precise image of where to look for problems. In addition does either the win32 (windows) or the xlib (linux) demo work for you? That would at least further narrow down the problem for me.

@ktb92677
Copy link
Author

ktb92677 commented Jul 1, 2015

Hey! So sorry for taking so long to get back to you here, I have finally got it to work after a bit of tinkering. A few extra notes here on your example:

This line -> void *memory = malloc(MEMORY_SIZE) needs a semi colon

This line -> struct gui_font font = {...}; is a bit ambigous... looked at examples and this component "gui_handle userdata;" is still a bit fuzzy on my end.

This line -> "len = gui_panel_edit(&layout, buffer, len, 256, &active, GUI_INPUT_DEFAULT);" doesn't quite work :)

gui_panel_init(&panel, 50, 50, 220, 170,
GUI_PANEL_BORDER|GUI_PANEL_MOVEABLE|
GUI_PANEL_CLOSEABLE|GUI_PANEL_SCALEABLE|
GUI_PANEL_MINIMIZABLE, &config, &buffer); For this line config and buffer need to be swapped

gui_command_buffer_init_fixed(buffer, memory, MEMORY_SIZE, GUI_CLIP); Need "&" prior to "buffer"

Anyways thanks! I'll be in touch soon if I see anymore issues

@ktb92677
Copy link
Author

ktb92677 commented Jul 2, 2015

After further review I will recant one of my statements

This line -> "len = gui_panel_edit(&layout, buffer, len, 256, &active, GUI_INPUT_DEFAULT);" doesn't quite work :). This line actually works!

Thank you for your time!

@ktb92677
Copy link
Author

ktb92677 commented Jul 2, 2015

Another note, I noticed on your example the edges of most of the objects are rounded, however on my rendering the edges are not rounded. I am not using the scissor function currently, could this be the cause?

@ktb92677
Copy link
Author

ktb92677 commented Jul 2, 2015

Another thing to mention here. For input on the code for: gui_input_char. Could you instead of requesting for a glyph (not entirely sure what this even is?) could you override it or something to just request for a char? Thanks so much!

@vurtun
Copy link
Owner

vurtun commented Jul 2, 2015

Hey, thanks for a good amount of feedback.
I hopefully fixed all bugs and fleshed out the font handling in the example code.

I.) Font
The gui_handle in the font structure is just a union for referencing user data either as a pointer or as an integer ID. The reason is that OpenGL and nanovg use IDs for textures and in the case of nanovg fonts as well, while the rest of the world use pointers.

typedef union {
    void *ptr;
    gui_int id;
} gui_handle;

Now that you mentioned it I will probably have to write some more documentation and examples describing how to use images and fonts.

II.) Rounding
As for now I only have rounding in the x11 and nanovg demo. I implemented rounding in the win32 demo as well, but it looked extremely ugly. I will probably have to dig deeper into shape drawing under win32. As for the OpenGL demo maybe if I have some time I will implement it in the near future.
The actual rounding on the library side is quite simple. The rectangle command has a rounding radius attribute (called r in the command structure) which determines the roundness of a rectangle. So only the rectangle drawing function in the demos need to be extended to support rounding.

III.) Glyphes
A glyph describes an Unicode symbol in this case it is just an array with four elements since I use UTF-8, so an ASCII character only needs to be placed into the first element in the glyph array.

typedef gui_char gui_glyph[GUI_UTF_SIZE];

Since it was not obvious I divided the function call into an ASCII version gui_input_char and a UTF-8 version gui_input_glyph.

@ktb92677
Copy link
Author

ktb92677 commented Jul 2, 2015

Okay "gui_input_char" seems to be working well! Except the cursor on the input box now only seems to measure the length of the new characters and isn't adjusting correctly.

@vurtun
Copy link
Owner

vurtun commented Jul 2, 2015

Oh OK, that one is a really old bug that I previously fixed that now comes back to hunt me. I will probably not be able to fix this tonight so I will look into it tomorrow.

@ktb92677
Copy link
Author

ktb92677 commented Jul 2, 2015

Okay cool! I look forward to the fix

@vurtun
Copy link
Owner

vurtun commented Jul 3, 2015

It is really strange. Everything works perfect for me until a certain point. When I then add another symbol the text width is suddenly calculated wrong. Do you use my text width calculation function or do you have your own? If you have the same problem than I can at least remove the possibility that my string width calculation function is wrong.

@ktb92677
Copy link
Author

ktb92677 commented Jul 3, 2015

No, I use my own width calculation algorithm. I've tested it relatively thoroughly, and I'd like to say that my width algorithm is working just fine. (I can do some further tests on it if you would like though)

@vurtun
Copy link
Owner

vurtun commented Jul 3, 2015

No need. If we both have the same results and bug then it is probably on the library end of things.

@vurtun
Copy link
Owner

vurtun commented Jul 3, 2015

OK I think solved the problem. It actually has nothing directly to do with my library code. Instead my opengl font code does not have kerning therefore the text width calculation is not perfect and for some character combinations provides wrong values. At least the X11 and nanovg work as intended. This is why I did not see the bug previously since I worked mostly with nanovg. That being said it still sucks, since I have to rely on the fact that the user has kerning.
But it is strange that it at least in my case still draws text correctly.

@vurtun
Copy link
Owner

vurtun commented Jul 3, 2015

Does it work without the cursor? for example in the spinner. If so then you could just remove the show_cursor flag in the gui_panel_edit_base function. That wouldn't be perfect but still better than a cursor that is drawn incorrectly.

@vurtun vurtun closed this as completed Jul 4, 2015
@vurtun vurtun reopened this Jul 4, 2015
@vurtun
Copy link
Owner

vurtun commented Jul 4, 2015

As it looks now I will probably rewrite the way text is drawn in the edit box since I need to support arbitrary cursor position for coping and pasting and therefore will draw each character independently. Maybe with a little bit of luck kerning does not have to be provided, at least not for the cursor to work.

@vurtun vurtun closed this as completed Jul 4, 2015
@vurtun
Copy link
Owner

vurtun commented Jul 13, 2015

OK small update in the opengl font drawing example. I had a extremely stupid bug in my code and it the editbox and cursor handling now works as intended. So it had nothing to do with kerning but instead I was just to stupid to find a simple bug.

@ktb92677
Copy link
Author

Hey! So I've stuck with using the function "gui_panel_edit" as this was easier to implement compared to the "gui_panel_editbox" function that you showed, but looks like on the former function the backspace functionality is broken. I have implemented a temporary fix on my end however in the long run I'd like to start using the former function. The former function requires two parameters: a layout and a gui_edit_box. The gui_edit_box seems to be a new addition, and its elements are a bit foreign to me.

struct gui_edit_box {
gui_edit_buffer buffer;
gui_bool active;
gui_size cursor;
gui_size glyphes;
struct gui_clipboard clip;
gui_filter filter;
};

I understand the first 2 elements as they are the same as are included in the original "gui_panel_edit" function. However the rest are strange to me. Could you please describe what these are?

Also could you set up an editbox that is a password field?

Thanks as always!

@vurtun
Copy link
Owner

vurtun commented Jul 30, 2015

Hey,
is the buggy backspace on your part or on mine? I am currently rewriting big parts of the library
and do not have working code right at this moment to test, but previously it seemed to work fine.
I will check again as soon as I have a stable build again.
As for the gui_edit_box you should use the gui_edit_box_init function to initialize it instead of directly setting the data. But that still leaves the gui_clipboard and gui_filter to explain.
The gui_clipboard is for copying and pasting into/out of the edit buffer and provides two callbacks and a userdata handle. The callbacks have the following definitions:
void gui_copy_f(gui_handle userdata, const char *text, gui_size byte_size)
void gui_paste_f(gui_handle userdata, char *buffer, gui_size max)
So to create a clipboard you just add one or both of these callbacks to the clipboard:

struct gui_clipboard clip;
clip.userdata = your_os_data_clipboard;
clip.copy = your_os_clipboard_copy_callback;
clip.paste = your_os_clipboard_paste_callback;

alternatively you can just pass NULL in the gui_edit_box_init function which deactivates the
copy & paste functionality.
Then for the gui_filter. The gui_filter callback is defined as:
gui_bool gui_filter(gui_long unicode).
Its main purpose is to provide a way to limit the characters that are allowed to be added into the editbox field. A number of basic filters are already implemented like gui_filter_input_default for anything goes or gui_filter_input_ascii and gui_filter_input_float. But if you do not need a filter then just pass NULL in the gui_edit_box_init function.
So finally for a complete example:

static gui_bool filter_numbers(gui_long unicode)
{
    if (unicode < '0' || unicode > '9')
        return gui_false;
    return gui_true;
}

static void copy_callback(gui_handle handle, const char *text, gui_size len)
{
    char buffer[1024];
    assert(len  < 1023);
    memcpy(buffer, text, len)
    buffer[len] = '\0'; 
    fprintf(stdout, "copied: %s\n", buffer);
}

static void paste_callback(gui_handle handle, char *buffer, gui_size max)
{
    const char *text = "abc"
    if (max < 3) return;
    memcpy(buffer, text, 3);
}

int main(void)
{
    /* clipboard does not have to be persistent it gets copied into the editbox */
    /* in the gui_edit_box_init function */
    struct gui_clipboard clip;
    clip.userdata.ptr = NULL;
    clip.copy = copy_callback;
    clip.paste = paste_callback;

    char buffer[256];
    struct gui_edit_box edit;
    /* if you do not want a clipboard and filter: */ 
    /* gui_edit_box_init_fixed(&edit, buffer, 256, NULL, NULL); */
    gui_edit_box_init_fixed(&edit, buffer, 256, &clip, filter_numbers);
}

This is a very simple and not very practical example but hopefully explains it a little bit better.
At the moment the editbox supports cursor updates by arrow keys and mouse clicks but does not support text selection but hopefully the next big update will have it, depending if I get it to work. This could in hand change the copy and paste callbacks a little bit.

So hopefully I will have a new big update this weekend done and I will write an Issue where I will extensively describe all changes.

@vurtun
Copy link
Owner

vurtun commented Jul 30, 2015

I have my code back in a working state and checked if backspace is bugged for the gui_panel_edit widget but everything for me works, so I don't have any idea where the problem could lie in.

@ktb92677
Copy link
Author

Hmm, that's strange. It is still not working for my end. The character is removed from the string but the cursor is not updated. It's almost as if it replaces the character with a space. I have looked around in my code for a bug and I can't seem to find one. For now I'll just try and implement the edit box instead. I'm looking forward to your next big update!

@ktb92677
Copy link
Author

I also noticed that on your OpenGL example the field "case GUI_COMMAND_IMAGE:" was not initialized. Could you provide an example of this? (I'd like to start drawing pixel buffers there). Thanks!

@vurtun
Copy link
Owner

vurtun commented Jul 30, 2015

Hmm,
the problem with the backspace sounds to me like a wrong text width calculation. Is the cursor otherwise correct or do you have glitches for example in combinations with 'm'? That was at least my last bug in context with the gui_panel_edit widget. Other than that I have no idea at least at the moment.
The image handling inside the library is a bigger topic so this will like always take some time to explain. OK first of the library does not have the concept of an image instead an image is just a pointer or id to a user object and if needed a rectangle that describes a sub referenced image to draw.
In the library every image is created by calling the gui_image_xxx and gui_subimage_xxx calls which return a gui_image struct which is used for every widget that uses an image. This is already everything that needs to be done at least on the widget side. The real work lies in the command execution since images are mainly a drawing problem and less a GUI problem. So instead of trying to explain it directly I will first show an example:

switch (cmd->type) {
    case GUI_COMMAND_IMAGE: {
        const struct gui_command_image *i = gui_command(image, cmd);
        if (gui_image_is_subimage(&i->img))
            draw_image(i->img.handle.ptr, i->x, i->y, i->w, i->h, i->img.region.x, i->img.region.y, i->img.region.w, i->img.region.h);
        else draw_image(i->img.handle.ptr, i->x, i->y, i->w, i->h);
    } break;
}

OK now to explain what I am doing here. First like always the general command is cast to the right command type. Then you have to check if the complete image needs to be drawn or only a subset of the image. To check if the image inside the command uses only a sub region the gui_image_is_subimage function is provided. The draw_image calls in this example are only place holders and should be replaced with your own functions. In addition if you do not need subimages and do not use them you can remove the draw_image call in the if-branch and only provide a way to draw a complete image. The image handle inside the gui_image struct inside the command functions is exactly like the gui_handle in the font structure and only points to your image data or ID that has been provided previously in the gui_image_xxx or gui_subimage_xxx call. So basically the image is only passed through the GUI and is only provided with a position and size to draw to.

@vurtun
Copy link
Owner

vurtun commented Aug 2, 2015

I just read that you requested for a password like editobox. Sorry that I did not replied on that issue. The password editbox shouldn't be a big problem I will take a look into the issue and provide it ASAP.

Small update on the clipboard in the editbox. Since the editbox got reworked and now supports text selection (even though it is a little bit shitty and I have to keep on iterating on it) the paste callback changed as well. The demo now has a example for the editbox and system clipboard as well. So you can have a look if you did not get it to work. But for short here is a small example for the new version:

static gui_bool filter_numbers(gui_long unicode)
{
    if (unicode < '0' || unicode > '9')
        return gui_false;
    return gui_true;
}

static void copy_callback(gui_handle handle, const char *text, gui_size len)
{
    char buffer[1024];
    assert(len  < 1023);
    memcpy(buffer, text, len)
    buffer[len] = '\0'; 
    fprintf(stdout, "copied: %s\n", buffer);
}

static void paste_callback(gui_handle handle, struct gui_edit_box *box)
{
    /* this adds the string "copied into the editbox "*/
    gui_edit_box_add(box, "copied", 5);
}

int main(void)
{
    /* clipboard does not have to be persistent it gets copied into the editbox */
    /* in the gui_edit_box_init function */
    struct gui_clipboard clip;
    clip.userdata.ptr = NULL;
    clip.copy = copy_callback;
    clip.paste = paste_callback;

    char buffer[256];
    struct gui_edit_box edit;
    /* if you do not want a clipboard and filter: */ 
    /* gui_edit_box_init_fixed(&edit, buffer, 256, NULL, NULL); */
    gui_edit_box_init_fixed(&edit, buffer, 256, &clip, filter_numbers);
}

@vurtun vurtun reopened this Aug 2, 2015
@vurtun vurtun closed this as completed Aug 21, 2015
vurtun pushed a commit that referenced this issue Nov 1, 2018
Syncing fork to the original repository
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants