Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for 9-slice/9-patch image for various widgets #69

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Github language settings
*.h linguist-language=c
*.c linguist-language=c
*.c linguist-language=c
641 changes: 496 additions & 145 deletions nuklear.h

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nuklear",
"version": "4.01.7",
"version": "4.02.0",
"repo": "Immediate-Mode-UI/Nuklear",
"description": "A small ANSI C gui toolkit",
"keywords": ["gl", "ui", "toolkit"],
Expand Down
1 change: 1 addition & 0 deletions src/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
/// - [yy]: Minor version with non-breaking API and library changes
/// - [zz]: Bug fix version with no direct changes to API
///
/// - 2020/03/07 (4.02.0) - Implemented 9-slice scaling support for widget styles and fixed inconsistent line endings problem
/// - 2020/03/06 (4.01.7) - Fix bug where width padding was applied twice
/// - 2020/02/06 (4.01.6) - Update stb_truetype.h and stb_rect_pack.h and separate them
/// - 2019/12/10 (4.01.5) - Fix off-by-one error in NK_INTERSECT
Expand Down
45 changes: 27 additions & 18 deletions src/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def omit_includes(str, files):
return str

def fix_comments(str):
return re.sub(r"//(.*)(\n|$)", "/* \\1 */\\2", str)
return re.sub(r"//(.*)(" + os.linesep + r"|$)", "/* \\1 */\\2", str)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't look correct to me (this shouldn't be dependent on the environment in which this script is being executed). I think this should actually be hard coded - i.e. something like

re.sub(r"//(.*)(\r\n|\r|\n|$)", "/* \\1 */\\2", str)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will, for some bizzare reason, always give priority to \n. This results in each comment being replaced with \r /* comment */ \n

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently I need to learn Python regexes better 😢. I think the issue is with the $ character, but I think the easiest thing would be to rewrite it to simply re.sub( "//([^\r\n]*)\r?\n?", "/* \\1 */\n", s ). Does this work with python 2.x on your system?

Also if we're already at it, we should discourage the use of str as variable label as it's a keyword in Python.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with that one is that it appends LF instead of the system-specific newline. I think it might be best to just completely remove the comment replacing feature, as // is fully supported in C99 and later, and in C90 if strict mode is not used.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with that one is that it appends LF instead of the system-specific newline.

That was my goal 😉.

I think it might be best to just completely remove the comment replacing feature, as // is fully supported in C99 and later, and in C90 if strict mode is not used.

We're trying to be strictly C89 compatible for good reasons (and this presumably won't change during the coming few years). That's why we introduced the "replacing feature".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But of course, I could write the replacement feature in POSIX shell and assume each Windows dev has git for windows installed allowing them to run paq.sh and remove paq.bat completely. But I'd prefer leaving it up to the build.py script.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was my goal 😉.

See my reply below as to why this isn't recommended.

But of course, I could write the replacement feature in POSIX shell and assume each Windows dev has git for windows installed allowing them to run paq.sh and remove paq.bat completely. But I'd prefer leaving it up to the build.py script.

I'm not sure if this would be a good assumption to make. Somehow we need to fix the regex so that it searches for the line-endings in the order that they are specified, instead of always giving precedence to \n.


# Main start
# ==========
Expand All @@ -83,6 +83,12 @@ def fix_comments(str):
print_help()
exit()

# Python 2.x Windows fix for newline madness
# ==========
if sys.platform == "win32":
import os, msvcrt
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)

intro_files = []
pub_files = []
priv_files1 = []
Expand Down Expand Up @@ -129,39 +135,42 @@ def fix_comments(str):

# Print concatenated output
# -------------------------
print("/*")
sys.stdout.write("/*" + os.linesep)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to admit I still can't grasp using os.linesep as this script should deterministically output stream of bytes independent from the platform it is being executed on.

I understand that we have to fight some corner cases of Python behavior (I also accept patches regarding Python 2.x behavior even if it's already after final EOL), but basically using os.linesep in this script in general doesn't seem like this fighting against Python. I don't run Windows, but I'm considering asking my good friend who runs Windows to take a look at this as this smells kind of fishy 😉.

Thoughts?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I have no idea on this one. Windows and Python oddities are not something i deal with often.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is with print on Windows with Python 2.x (I have 2.7). For some reason, it always uses LF instead of CRLF. It is silly that we have to work around this kind of thing, which is (apparently) resolved in Python 3.x, but too many programs still rely on 2.x. Would you be willing to make the script only work with Python 3.x? Most developers should have 3.x on their systems nowadays anyway, and it's simple to install if they don't have it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason, it always uses LF instead of CRLF.

Hm, but that's exactly the behavior we require, don't we?

Would you be willing to make the script only work with Python 3.x?

Yeah, that's also an option I'm totally OK with.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Hejsil sounds plausible - what about just replacing .replace( '\r', '' ) on all opened files with wb (i.e. binary mode). That'd do, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that could work. As long as this file is generated with one consistent line ending then I think git will be happy.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry if I wasn't clear enough, but where exactly do the multiple line-endings come from?

print() on Windows in Python 2.x (or at least in 2.7) appends \n to the end of the string you pass it. Git on Windows converts all line-endings to \r\n when you checkout, at least by default.

Hejsil explained it a bit clearer than I did, it seems.

what about just replacing .replace( '\r', '' ) on all opened files with wb (i.e. binary mode). That'd do, right?

I'm not sure we should start doing this kind of thing, but if it works, it works. I still feel that simply requiring that the script be run with Py3 would be a better decision.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do agree we can restrict users to Python 3, but I still like the explicit replace (with a comment explaining "why") because that makes it fully explicit.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should be a separate pull request? Then we could get this one merged ;)

for f in intro_files:
sys.stdout.write(open(f, 'r').read())
print("*/")
sys.stdout.write(open(f, 'rb').read())
sys.stdout.write("*/" + os.linesep)

# print(os.linesep + "#ifndef " + macro + "_SINGLE_HEADER");
# print("#define " + macro + "_SINGLE_HEADER");
print("#ifndef NK_SINGLE_FILE");
print(" #define NK_SINGLE_FILE");
print("#endif");
print("");
sys.stdout.write("#ifndef NK_SINGLE_FILE" + os.linesep);
sys.stdout.write(" #define NK_SINGLE_FILE" + os.linesep);
sys.stdout.write("#endif" + os.linesep);
sys.stdout.write(os.linesep);

for f in pub_files:
sys.stdout.write(open(f, 'r').read())
sys.stdout.write(open(f, 'rb').read())
# print("#endif /* " + macro + "_SINGLE_HEADER */");

print(os.linesep + "#ifdef " + macro + "_IMPLEMENTATION");
print("");
sys.stdout.write(os.linesep + "#ifdef " + macro + "_IMPLEMENTATION" + os.linesep)

for f in priv_files1:
print(omit_includes(open(f, 'r').read(),
sys.stdout.write(omit_includes(open(f, 'rb').read(),
pub_files + priv_files1 + priv_files2 + extern_files))
sys.stdout.write(os.linesep)

for f in extern_files:
print(fix_comments(open(f, 'r').read()))
sys.stdout.write(fix_comments(open(f, 'rb').read()))
sys.stdout.write(os.linesep)

for f in priv_files2:
print(omit_includes(open(f, 'r').read(),
sys.stdout.write(omit_includes(open(f, 'rb').read(),
pub_files + priv_files1 + priv_files2 + extern_files))
sys.stdout.write(os.linesep)

print("#endif /* " + macro + "_IMPLEMENTATION */");
sys.stdout.write("#endif /* " + macro + "_IMPLEMENTATION */" + os.linesep);

print(os.linesep + "/*")
sys.stdout.write(os.linesep + "/*" + os.linesep)
for f in outro_files:
sys.stdout.write(open(f, 'r').read())
print("*/" + os.linesep)
sys.stdout.write(open(f, 'rb').read())
sys.stdout.write("*/" + os.linesep)

31 changes: 24 additions & 7 deletions src/nuklear.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,8 @@ struct nk_rect {float x,y,w,h;};
struct nk_recti {short x,y,w,h;};
typedef char nk_glyph[NK_UTF_SIZE];
typedef union {void *ptr; int id;} nk_handle;
struct nk_image {nk_handle handle;unsigned short w,h;unsigned short region[4];};
struct nk_image {nk_handle handle; nk_ushort w, h; nk_ushort region[4];};
struct nk_9slice {struct nk_image img; nk_ushort l, t, r, b;};
struct nk_cursor {struct nk_image img; struct nk_vec2 size, offset;};
struct nk_scroll {nk_uint x, y;};

Expand Down Expand Up @@ -3477,9 +3478,21 @@ NK_API struct nk_image nk_image_handle(nk_handle);
NK_API struct nk_image nk_image_ptr(void*);
NK_API struct nk_image nk_image_id(int);
NK_API int nk_image_is_subimage(const struct nk_image* img);
NK_API struct nk_image nk_subimage_ptr(void*, unsigned short w, unsigned short h, struct nk_rect sub_region);
NK_API struct nk_image nk_subimage_id(int, unsigned short w, unsigned short h, struct nk_rect sub_region);
NK_API struct nk_image nk_subimage_handle(nk_handle, unsigned short w, unsigned short h, struct nk_rect sub_region);
NK_API struct nk_image nk_subimage_ptr(void*, nk_ushort w, nk_ushort h, struct nk_rect sub_region);
NK_API struct nk_image nk_subimage_id(int, nk_ushort w, nk_ushort h, struct nk_rect sub_region);
NK_API struct nk_image nk_subimage_handle(nk_handle, nk_ushort w, nk_ushort h, struct nk_rect sub_region);
/* =============================================================================
*
* 9-SLICE
*
* ============================================================================= */
NK_API struct nk_9slice nk_9slice_handle(nk_handle, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);
NK_API struct nk_9slice nk_9slice_ptr(void*, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);
NK_API struct nk_9slice nk_9slice_id(int, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);
NK_API int nk_9slice_is_sub9slice(const struct nk_9slice* img);
NK_API struct nk_9slice nk_sub9slice_ptr(void*, nk_ushort w, nk_ushort h, struct nk_rect sub_region, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);
NK_API struct nk_9slice nk_sub9slice_id(int, nk_ushort w, nk_ushort h, struct nk_rect sub_region, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);
NK_API struct nk_9slice nk_sub9slice_handle(nk_handle, nk_ushort w, nk_ushort h, struct nk_rect sub_region, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);
/* =============================================================================
*
* MATH
Expand Down Expand Up @@ -4368,6 +4381,7 @@ NK_API void nk_fill_polygon(struct nk_command_buffer*, float*, int point_count,

/* misc */
NK_API void nk_draw_image(struct nk_command_buffer*, struct nk_rect, const struct nk_image*, struct nk_color);
NK_API void nk_draw_9slice(struct nk_command_buffer*, struct nk_rect, const struct nk_9slice*, struct nk_color);
NK_API void nk_draw_text(struct nk_command_buffer*, struct nk_rect, const char *text, int len, const struct nk_user_font*, struct nk_color, struct nk_color);
NK_API void nk_push_scissor(struct nk_command_buffer*, struct nk_rect);
NK_API void nk_push_custom(struct nk_command_buffer*, struct nk_rect, nk_command_custom_callback, nk_handle usr);
Expand Down Expand Up @@ -4585,12 +4599,14 @@ NK_API void nk_draw_list_push_userdata(struct nk_draw_list*, nk_handle userdata)
* ===============================================================*/
enum nk_style_item_type {
NK_STYLE_ITEM_COLOR,
NK_STYLE_ITEM_IMAGE
NK_STYLE_ITEM_IMAGE,
NK_STYLE_ITEM_9SLICE
};

union nk_style_item_data {
struct nk_image image;
struct nk_color color;
struct nk_image image;
struct nk_9slice slice;
};

struct nk_style_item {
Expand Down Expand Up @@ -5016,8 +5032,9 @@ struct nk_style {
struct nk_style_window window;
};

NK_API struct nk_style_item nk_style_item_image(struct nk_image img);
NK_API struct nk_style_item nk_style_item_color(struct nk_color);
NK_API struct nk_style_item nk_style_item_image(struct nk_image img);
NK_API struct nk_style_item nk_style_item_9slice(struct nk_9slice slice);
NK_API struct nk_style_item nk_style_item_hide(void);

/*==============================================================
Expand Down
106 changes: 106 additions & 0 deletions src/nuklear_9slice.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#include "nuklear.h"
#include "nuklear_internal.h"

/* ===============================================================
*
* 9-SLICE
*
* ===============================================================*/
NK_API struct nk_9slice
nk_sub9slice_ptr(void *ptr, nk_ushort w, nk_ushort h, struct nk_rect rgn, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
{
struct nk_9slice s;
nk_zero(&s, sizeof(s));
struct nk_image *i = (struct nk_image*)&s;
i->handle.ptr = ptr;
i->w = w; i->h = h;
i->region[0] = (nk_ushort)rgn.x;
i->region[1] = (nk_ushort)rgn.y;
i->region[2] = (nk_ushort)rgn.w;
i->region[3] = (nk_ushort)rgn.h;
s.l = l; s.t = t; s.r = r; s.b = b;
return s;
}
NK_API struct nk_9slice
nk_sub9slice_id(int id, nk_ushort w, nk_ushort h, struct nk_rect rgn, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
{
struct nk_9slice s;
nk_zero(&s, sizeof(s));
struct nk_image *i = (struct nk_image*)&s;
i->handle.id = id;
i->w = w; i->h = h;
i->region[0] = (nk_ushort)rgn.x;
i->region[1] = (nk_ushort)rgn.y;
i->region[2] = (nk_ushort)rgn.w;
i->region[3] = (nk_ushort)rgn.h;
s.l = l; s.t = t; s.r = r; s.b = b;
return s;
}
NK_API struct nk_9slice
nk_sub9slice_handle(nk_handle handle, nk_ushort w, nk_ushort h, struct nk_rect rgn, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
{
struct nk_9slice s;
nk_zero(&s, sizeof(s));
struct nk_image *i = (struct nk_image*)&s;
i->handle = handle;
i->w = w; i->h = h;
i->region[0] = (nk_ushort)rgn.x;
i->region[1] = (nk_ushort)rgn.y;
i->region[2] = (nk_ushort)rgn.w;
i->region[3] = (nk_ushort)rgn.h;
s.l = l; s.t = t; s.r = r; s.b = b;
return s;
}
NK_API struct nk_9slice
nk_9slice_handle(nk_handle handle, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
{
struct nk_9slice s;
nk_zero(&s, sizeof(s));
struct nk_image *i = (struct nk_image*)&s;
i->handle = handle;
i->w = 0; i->h = 0;
i->region[0] = 0;
i->region[1] = 0;
i->region[2] = 0;
i->region[3] = 0;
s.l = l; s.t = t; s.r = r; s.b = b;
return s;
}
NK_API struct nk_9slice
nk_9slice_ptr(void *ptr, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
{
struct nk_9slice s;
nk_zero(&s, sizeof(s));
struct nk_image *i = (struct nk_image*)&s;
NK_ASSERT(ptr);
i->handle.ptr = ptr;
i->w = 0; i->h = 0;
i->region[0] = 0;
i->region[1] = 0;
i->region[2] = 0;
i->region[3] = 0;
s.l = l; s.t = t; s.r = r; s.b = b;
return s;
}
NK_API struct nk_9slice
nk_9slice_id(int id, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
{
struct nk_9slice s;
nk_zero(&s, sizeof(s));
struct nk_image *i = (struct nk_image*)&s;
i->handle.id = id;
i->w = 0; i->h = 0;
i->region[0] = 0;
i->region[1] = 0;
i->region[2] = 0;
i->region[3] = 0;
s.l = l; s.t = t; s.r = r; s.b = b;
return s;
}
NK_API int
nk_9slice_is_sub9slice(const struct nk_9slice* slice)
{
NK_ASSERT(slice);
return !(slice->img.w == 0 && slice->img.h == 0);
}

16 changes: 11 additions & 5 deletions src/nuklear_button.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,17 @@ nk_draw_button(struct nk_command_buffer *out,
background = &style->active;
else background = &style->normal;

if (background->type == NK_STYLE_ITEM_IMAGE) {
nk_draw_image(out, *bounds, &background->data.image, nk_white);
} else {
nk_fill_rect(out, *bounds, style->rounding, background->data.color);
nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);
switch(background->type) {
case NK_STYLE_ITEM_IMAGE:
nk_draw_image(out, *bounds, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_9SLICE:
nk_draw_9slice(out, *bounds, &background->data.slice, nk_white);
break;
case NK_STYLE_ITEM_COLOR:
nk_fill_rect(out, *bounds, style->rounding, background->data.color);
nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);
break;
}
return background;
}
Expand Down
19 changes: 13 additions & 6 deletions src/nuklear_chart.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,19 @@ nk_chart_begin_colored(struct nk_context *ctx, enum nk_chart_type type,

/* draw chart background */
background = &style->background;
if (background->type == NK_STYLE_ITEM_IMAGE) {
nk_draw_image(&win->buffer, bounds, &background->data.image, nk_white);
} else {
nk_fill_rect(&win->buffer, bounds, style->rounding, style->border_color);
nk_fill_rect(&win->buffer, nk_shrink_rect(bounds, style->border),
style->rounding, style->background.data.color);

switch(background->type) {
case NK_STYLE_ITEM_IMAGE:
nk_draw_image(&win->buffer, bounds, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_9SLICE:
nk_draw_9slice(&win->buffer, bounds, &background->data.slice, nk_white);
break;
case NK_STYLE_ITEM_COLOR:
nk_fill_rect(&win->buffer, bounds, style->rounding, style->border_color);
nk_fill_rect(&win->buffer, nk_shrink_rect(bounds, style->border),
style->rounding, style->background.data.color);
break;
}
return 1;
}
Expand Down
Loading