42_Scale

a small software to create and edit 42 (.yaml) scale files easily
Log | Files | Refs | Submodules | README | LICENSE | git clone https://git.ne02ptzero.me/git/42_Scale

commit bdafb87d5900eff7bf082f11539c47030f70c9e8
parent c92b882fd4c7f3cc3d25d7b125d65952f5e433f5
Author: Ne02ptzero <louis@ne02ptzero.me>
Date:   Mon, 25 Apr 2016 04:06:34 +0200

Add(Graphic): Basic interface

Diffstat:
A.ycm_extra_conf.pyc | 0
MMakefile | 7++++---
Minc/scale.h | 69+++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Asrcs/graphic.c | 477+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrcs/helpers.c | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrcs/main.c | 11++++++++++-
Msrcs/yaml.c | 51+++++++++++++++++++++++++++++++--------------------
7 files changed, 705 insertions(+), 44 deletions(-)

diff --git a/.ycm_extra_conf.pyc b/.ycm_extra_conf.pyc Binary files differ. diff --git a/Makefile b/Makefile @@ -1,8 +1,8 @@ NAME = 42_scale CC = gcc -CFLAGS = -Wall -Wextra -Werror -g -O2 -std=c99 -rdynamic +CFLAGS = -g -O2 -std=c99 -rdynamic -INCS = -I inc/ -I inc/nuklear/ -I ~/.brew/include +INCS = -I inc/ -I inc/nuklear/ -I ~/.brew/include -I ./libs/libyaml/include/ SRCS = $(wildcard srcs/*.c) OBJS = $(SRCS:%.c=%.o) @@ -11,7 +11,8 @@ ifeq ($(UNAME_S),Darwin) LIBS = -lglfw3 -framework OpenGL -lm -lGLEW LIBS_DIR = -L ~/.brew/lib else - LIBS = -lglfw -lGL -lm -lGLU -lGLEW + LIBS = -lglfw -lGL -lm -lGLU -lGLEW -lyaml + LIBS_DIR = -L ./libs/libyaml/src/.libs/ endif diff --git a/inc/scale.h b/inc/scale.h @@ -1,15 +1,22 @@ #ifndef __SCALE__ # define __SCALE__ -# include <nuklear.h> # include <stdlib.h> # include <stdio.h> # include <stddef.h> # include <execinfo.h> # include <unistd.h> # include <yaml.h> +# include <stdbool.h> +# include <GL/glew.h> +# include <GLFW/glfw3.h> +# include <math.h> +# include <assert.h> # define ERROR(...) printf("\033[1;31mFATAL ERROR:\033[0m 42_scale must stop. \n\033[0;31m> Reason: \033[0m"); printf(__VA_ARGS__); print_trace(); _exit(1); +# define WINDOW_WIDTH 800 +# define WINDOW_HEIGHT 600 +# define MAX_INPUTS 9 enum { LANG_FR, @@ -19,7 +26,10 @@ enum { enum { R_BOOL, - R_MULTI, + R_MULTI +}; + +enum { R_STAND, R_BONUS }; @@ -29,52 +39,71 @@ enum { * NOTE: MD = Markdown */ +typedef struct s_entry scale_entry; typedef struct s_skills scale_skills; typedef struct s_questions scale_questions; typedef struct s_sections scale_sections; typedef struct s_scale scale; +struct s_entry { + char *buf; // Entry buffer + int len; // Len of the buffer + int val; // Alternate value + bool bol; // Alternate value +}; + struct s_skills { - int percent; // Percentage (1-100) value of the skill - char *name; // Skill name + scale_entry percent; // Percentage (1-100) value of the skill + scale_entry name; // Skill name struct s_skills *next; // Pointer to the next skill }; struct s_questions { - char *name; // Name of the question - char *guidelines; // Guidelines of the question (MD) - int rating; // Rating of the question (R_BOOL | R_MULTI) - int kind; // Type of question (R_STAND | R_BONUS) + scale_entry name; // Name of the question + scale_entry guidelines; // Guidelines of the question (MD) + scale_entry rating; // Rating of the question (R_BOOL | R_MULTI) + scale_entry kind; // Type of question (R_STAND | R_BONUS) struct s_skills *skills; // Pointer to s_skills struct struct s_questions *next; // Pointer to the next question }; struct s_sections { - char *name; // Name of the section - char *description; // Description of the section + scale_entry name; // Name of the section + scale_entry description; // Description of the section struct s_questions *questions; // Pointer to s_questions struct struct s_sections *next; // Pointer to the next section }; struct s_scale { - char *name; // Name of the subject - int lang; // Language of the scale (Enum value LANG_*) - char *comment; // Comment about the scale - char *intro; // Introduction about the scale (MD) - char *disclaimer; // Disclaimer about the scale (MD) - char *guidelines; // Guidelines of the scale (MD) - int correction_n; // Corrections number + scale_entry name; // Name of the subject + scale_entry lang; // Language of the scale (Enum value LANG_*) + scale_entry comment; // Comment about the scale + scale_entry intro; // Introduction about the scale (MD) + scale_entry disclaimer; // Disclaimer about the scale (MD) + scale_entry guidelines; // Guidelines of the scale (MD) + scale_entry correction_n; // Corrections number + scale_entry is_primary; // Always true + scale_entry duration; // Duration of the scale, with a 5 multiplier (1 = 5, 2 = 10, ...) struct s_sections *sections; // Pointer to s_sections structs }; + + /* HELPERS (helpers.c) */ -void print_trace(void); -char *m_strcpy(yaml_token_t token); -void scale_debug(scale *res); +void print_trace(void); +scale_entry m_strcpy(yaml_token_t token); +void scale_debug(scale *res); +int count_lines(char *s); +void add_section(scale_sections *s, char *name); +void add_question(scale_sections *s, char *name, int j); +void add_skills(scale_questions *sk, int val, char *name); /* YAML (yaml.c) */ scale *read_scale(FILE *fd); +/* GRAPHIC (graphic.c) */ +void window(scale *s); + #endif diff --git a/srcs/graphic.c b/srcs/graphic.c @@ -0,0 +1,477 @@ +# include <scale.h> +# define NK_INCLUDE_FIXED_TYPES +# define NK_INCLUDE_STANDARD_IO +# define NK_INCLUDE_DEFAULT_ALLOCATOR +# define NK_INCLUDE_VERTEX_BUFFER_OUTPUT +# define NK_INCLUDE_FONT_BAKING +# define NK_INCLUDE_DEFAULT_FONT +# define NK_IMPLEMENTATION +# include <nuklear.h> +#ifdef __APPLE__ + #define NK_SHADER_VERSION "#version 150\n" +#else + #define NK_SHADER_VERSION "#version 300 es\n" +#endif +# define MAX_VERTEX_MEMORY 512 * 1024 +# define MAX_ELEMENT_MEMORY 128 * 1024 +# define UNUSED(a) (void)a + + + +struct device { + struct nk_buffer cmds; + struct nk_draw_null_texture null; + GLuint vbo, vao, ebo; + GLuint prog; + GLuint vert_shdr; + GLuint frag_shdr; + GLint attrib_pos; + GLint attrib_uv; + GLint attrib_col; + GLint uniform_tex; + GLint uniform_proj; + GLuint font_tex; +}; + +static void text_input(GLFWwindow *win, unsigned int codepoint) +{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);} +static void scroll_input(GLFWwindow *win, double _, double yoff) +{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), (float)yoff);} + + static void +device_init(struct device *dev) +{ + GLint status; + static const GLchar *vertex_shader = + NK_SHADER_VERSION + "uniform mat4 ProjMtx;\n" + "in vec2 Position;\n" + "in vec2 TexCoord;\n" + "in vec4 Color;\n" + "out vec2 Frag_UV;\n" + "out vec4 Frag_Color;\n" + "void main() {\n" + " Frag_UV = TexCoord;\n" + " Frag_Color = Color;\n" + " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" + "}\n"; + static const GLchar *fragment_shader = + NK_SHADER_VERSION + "precision mediump float;\n" + "uniform sampler2D Texture;\n" + "in vec2 Frag_UV;\n" + "in vec4 Frag_Color;\n" + "out vec4 Out_Color;\n" + "void main(){\n" + " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" + "}\n"; + + nk_buffer_init_default(&dev->cmds); + dev->prog = glCreateProgram(); + dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER); + dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0); + glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0); + glCompileShader(dev->vert_shdr); + glCompileShader(dev->frag_shdr); + glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status); + assert(status == GL_TRUE); + glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status); + assert(status == GL_TRUE); + glAttachShader(dev->prog, dev->vert_shdr); + glAttachShader(dev->prog, dev->frag_shdr); + glLinkProgram(dev->prog); + glGetProgramiv(dev->prog, GL_LINK_STATUS, &status); + assert(status == GL_TRUE); + + dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture"); + dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx"); + dev->attrib_pos = glGetAttribLocation(dev->prog, "Position"); + dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord"); + dev->attrib_col = glGetAttribLocation(dev->prog, "Color"); + + { + /* buffer setup */ + GLsizei vs = sizeof(struct nk_draw_vertex); + size_t vp = offsetof(struct nk_draw_vertex, position); + size_t vt = offsetof(struct nk_draw_vertex, uv); + size_t vc = offsetof(struct nk_draw_vertex, col); + + glGenBuffers(1, &dev->vbo); + glGenBuffers(1, &dev->ebo); + glGenVertexArrays(1, &dev->vao); + + glBindVertexArray(dev->vao); + glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); + + glEnableVertexAttribArray((GLuint)dev->attrib_pos); + glEnableVertexAttribArray((GLuint)dev->attrib_uv); + glEnableVertexAttribArray((GLuint)dev->attrib_col); + + glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp); + glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt); + glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc); + } + + glBindTexture(GL_TEXTURE_2D, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindVertexArray(0); +} + + static void +device_upload_atlas(struct device *dev, const void *image, int width, int height) +{ + glGenTextures(1, &dev->font_tex); + glBindTexture(GL_TEXTURE_2D, dev->font_tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, image); +} + + static void +device_shutdown(struct device *dev) +{ + glDetachShader(dev->prog, dev->vert_shdr); + glDetachShader(dev->prog, dev->frag_shdr); + glDeleteShader(dev->vert_shdr); + glDeleteShader(dev->frag_shdr); + glDeleteProgram(dev->prog); + glDeleteTextures(1, &dev->font_tex); + glDeleteBuffers(1, &dev->vbo); + glDeleteBuffers(1, &dev->ebo); + nk_buffer_free(&dev->cmds); +} + + static void +device_draw(struct device *dev, struct nk_context *ctx, int width, int height, + enum nk_anti_aliasing AA) +{ + GLint last_prog, last_tex; + GLint last_ebo, last_vbo, last_vao; + GLfloat ortho[4][4] = { + {2.0f, 0.0f, 0.0f, 0.0f}, + {0.0f,-2.0f, 0.0f, 0.0f}, + {0.0f, 0.0f,-1.0f, 0.0f}, + {-1.0f,1.0f, 0.0f, 1.0f}, + }; + ortho[0][0] /= (GLfloat)width; + ortho[1][1] /= (GLfloat)height; + + /* save previous opengl state */ + glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex); + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao); + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo); + glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo); + + /* setup global state */ + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glEnable(GL_SCISSOR_TEST); + glActiveTexture(GL_TEXTURE0); + + /* setup program */ + glUseProgram(dev->prog); + glUniform1i(dev->uniform_tex, 0); + glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]); + { + /* convert from command queue into draw list and draw to screen */ + const struct nk_draw_command *cmd; + void *vertices, *elements; + const nk_draw_index *offset = NULL; + + /* allocate vertex and element buffer */ + glBindVertexArray(dev->vao); + glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); + + glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW); + + /* load draw vertices & elements directly into vertex + element buffer */ + vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); + elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY); + { + /* fill converting configuration */ + struct nk_convert_config config; + memset(&config, 0, sizeof(config)); + config.global_alpha = 1.0f; + config.shape_AA = AA; + config.line_AA = AA; + config.circle_segment_count = 22; + config.curve_segment_count = 22; + config.arc_segment_count = 22; + config.null = dev->null; + + /* setup buffers to load vertices and elements */ + {struct nk_buffer vbuf, ebuf; + nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY); + nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY); + nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);} + } + glUnmapBuffer(GL_ARRAY_BUFFER); + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); + + /* iterate over and execute each draw command */ + nk_draw_foreach(cmd, ctx, &dev->cmds) { + if (!cmd->elem_count) continue; + glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); + glScissor((GLint)cmd->clip_rect.x, + height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h), + (GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h); + glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); + offset += cmd->elem_count; + } + nk_clear(ctx); + } + + /* restore old state */ + glUseProgram((GLuint)last_prog); + glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex); + glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo); + glBindVertexArray((GLuint)last_vao); + glDisable(GL_SCISSOR_TEST); +} + +static void error_callback(int e, const char *d){ + ERROR("GLFW Error %d: %s\n", e, d); +} + +static GLFWwindow *init(struct nk_context *ctx, struct device *device) { + struct nk_font *font; + struct nk_font_atlas atlas; + GLFWwindow *win = 0x0; + const void *image; + int w, h; + + glfwSetErrorCallback(error_callback); + if (!glfwInit()) { + ERROR("Failed to init GLFW!\n"); + } + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); +#ifdef __APPLE__ + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); +#endif + win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "42_scale", NULL, NULL); + glfwMakeContextCurrent(win); + glfwSetWindowUserPointer(win, ctx); + glfwSetCharCallback(win, text_input); + glfwSetScrollCallback(win, scroll_input); + glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); + glewExperimental = 1; + if (glewInit() != GLEW_OK) { + ERROR("Failed to setup GLEW\n"); + } + device_init(device); + nk_font_atlas_init_default(&atlas); + nk_font_atlas_begin(&atlas); + font = nk_font_atlas_add_default(&atlas, 13.0f, NULL); + image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32); + device_upload_atlas(device, image, w, h); + nk_font_atlas_end(&atlas, nk_handle_id((int)device->font_tex), &device->null); + nk_init_default(ctx, &(font->handle)); + return win; +} + +void handle_input(struct nk_context *ctx, GLFWwindow *win) { + double x, y; + + nk_input_begin(ctx); + glfwPollEvents(); + nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS); + if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || + glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL)) { + nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_SHIFT, 1); + } else { + nk_input_key(ctx, NK_KEY_COPY, 0); + nk_input_key(ctx, NK_KEY_PASTE, 0); + nk_input_key(ctx, NK_KEY_CUT, 0); + nk_input_key(ctx, NK_KEY_SHIFT, 0); + } + glfwGetCursorPos(win, &x, &y); + nk_input_motion(ctx, (int)x, (int)y); + nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); + nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); + nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); + nk_input_end(ctx); +} + +void handle_window(scale *s, struct nk_context *ctx) { + struct nk_panel layout; + static const float ratio[] = {120, 150}, ratio2[] = {300, 150}; + const char *lang[] = {"English", "French", "LANG_RU"}; + int w_flag = NK_WINDOW_TITLE | NK_WINDOW_BORDER | + NK_WINDOW_CLOSABLE | NK_WINDOW_SCALABLE | NK_WINDOW_MOVABLE; + + if (nk_begin(ctx, &layout, "Main", nk_rect(10, 10, 600, WINDOW_HEIGHT * 1.5), w_flag)) { + nk_layout_row(ctx, NK_STATIC, 25, 2, ratio); + nk_label(ctx, "Subject name", NK_TEXT_LEFT); + nk_edit_string(ctx, NK_EDIT_FIELD, s->name.buf, &s->name.len, 64, nk_filter_default); + nk_label(ctx, "Language", NK_TEXT_LEFT); + s->lang.val = nk_combo(ctx, lang, 3, s->lang.val, 25); + nk_label(ctx, "Comment", NK_TEXT_LEFT); + nk_edit_string(ctx, NK_EDIT_FIELD, s->comment.buf, &s->comment.len, 64, nk_filter_default); + nk_label(ctx, "Correction", NK_TEXT_LEFT); + nk_property_int(ctx, "Number:", 0, &s->correction_n.val, 100.0f, 1, 1); + nk_label(ctx, "Correction", NK_TEXT_LEFT); + nk_property_int(ctx, "Duration:", 0, &s->duration.val, 100.0f, 1, 1); + nk_label(ctx, "Introduction", NK_TEXT_LEFT); + nk_layout_row_static(ctx, count_lines(s->intro.buf), 550, 1); + nk_edit_string(ctx, NK_EDIT_BOX, s->intro.buf, &s->intro.len, 2024, nk_filter_ascii); + nk_layout_row(ctx, NK_STATIC, 25, 2, ratio); + nk_label(ctx, "Guidelines", NK_TEXT_LEFT); + nk_layout_row_static(ctx, count_lines(s->guidelines.buf), 550, 1); + nk_edit_string(ctx, NK_EDIT_BOX | NK_COLOR_EDIT_CURSOR, s->guidelines.buf, &s->guidelines.len, 2024, nk_filter_ascii); + nk_layout_row_end(ctx); + } + nk_end(ctx); + + nk_flags active; + static char *new_section = 0x0, new_question[30][64]; + static int ns_len = 0, nq_len[30], nq_active[30], sk_add[64] = {0}; + const char *rating[] = {"Boolean", "Multi"}; + const char *kind[] = {"Standard", "Bonus"}; + const char *skills[] = {"Adaptation & Creativity", "Algorithms & AI", "Company experience", "DB & Data", + "Functionnal programming", "Graphics", "Group & interpersonal", "Imperative programming", + "Network & system administration", "Object-oriented programming", + "Organization", "Parallel computing", "Rigor", "Security", "Technology integration", "Unix", "Web"}; + int j = 0, q = 0, sk_totals_sd[30] = {0}, sk_totals_bs[30] = {0}; + if (!new_section) { + new_section = malloc(64); + } + if (nk_begin(ctx, &layout, "Sections", nk_rect(620, 10, 600, WINDOW_HEIGHT * 1.5), w_flag)) { + nk_layout_row(ctx, NK_STATIC, 25, 2, ratio); + active = nk_edit_string(ctx, NK_EDIT_FIELD|NK_EDIT_SIG_ENTER, new_section, &ns_len, 64, nk_filter_ascii); + if (nk_button_label(ctx, "Add a Section", NK_BUTTON_DEFAULT) || (active & NK_EDIT_COMMITED)) { + new_section[ns_len] = 0x0; + add_section(s->sections, new_section); + new_section = ""; + ns_len = 0; + } + for (scale_sections *it = s->sections; it; it = it->next, j++) { + if (nk_tree_push(ctx, NK_TREE_NODE, it->name.buf, NK_MINIMIZED)) { + nk_layout_row(ctx, NK_STATIC, 25, 2, ratio); + nk_label(ctx, "Add a Question", NK_TEXT_LEFT); + nq_active[j] = nk_edit_string(ctx, NK_EDIT_FIELD | NK_EDIT_SIG_ENTER, new_question[j], &nq_len[j], 64, nk_filter_ascii); + nk_label(ctx, "Description", NK_TEXT_LEFT); + nk_edit_string(ctx, NK_EDIT_FIELD, it->description.buf, &it->description.len, 64, nk_filter_default); + nk_layout_row_end(ctx); + for (scale_questions *it2 = it->questions; it2; it2 = it2->next, q++) { + if (nk_tree_push(ctx, NK_TREE_NODE, it2->name.buf, NK_MINIMIZED)) { + nk_label(ctx, "Guidelines", NK_TEXT_LEFT); + nk_layout_row_static(ctx, count_lines(it2->guidelines.buf), 550, 1); + nk_edit_string(ctx, NK_EDIT_BOX, it2->guidelines.buf, &it2->guidelines.len, 2024, nk_filter_ascii); + nk_layout_row(ctx, NK_STATIC, 25, 2, ratio); + nk_label(ctx, "Rating type", NK_TEXT_LEFT); + it2->rating.val = nk_combo(ctx, rating, 2, it2->rating.val, 25); + nk_label(ctx, "Kind", NK_TEXT_LEFT); + it2->kind.val = nk_combo(ctx, kind, 2, it2->kind.val, 25); + if (nk_tree_push(ctx, NK_TREE_NODE, "Skills", NK_MINIMIZED)) { + nk_layout_row(ctx, NK_STATIC, 25, 2, ratio2); + sk_add[q] = nk_combo(ctx, skills, 17, sk_add[q], 25); + if (nk_button_label(ctx, "Add a Skill", NK_BUTTON_DEFAULT)) { + add_skills(it2, sk_add[q], (char *)skills[q]); + sk_add[q] = 0; + } + for (scale_skills *sk = it2->skills; sk; sk = sk->next) { + nk_label(ctx, skills[sk->name.val], NK_TEXT_LEFT); + nk_property_int(ctx, "Percent:", 0, &sk->percent.val, 100.0f, 1, 1); + } + nk_tree_pop(ctx); + } + nk_tree_pop(ctx); + } + } + nk_tree_pop(ctx); + } + } + for (j = 0; j < 30; j++) { + if (nq_active[j] & NK_EDIT_COMMITED) { + new_question[j][nq_len[j]] = 0x0; + add_question(s->sections, new_question[j], j); + strcpy(new_question[j], ""); + nq_len[j] = 0; + } + } + } + nk_end(ctx); + for (scale_sections *it = s->sections; it; it = it->next, j++) { + for (scale_questions *it2 = it->questions; it2; it2 = it2->next) { + for (scale_skills *sk = it2->skills; sk; sk = sk->next) { + if (it2->kind.val == R_STAND) { + sk_totals_sd[sk->name.val] += sk->percent.val; + } else { + sk_totals_bs[sk->name.val] += sk->percent.val; + } + } + } + } + if (nk_begin(ctx, &layout, "Skills totals", nk_rect(1250, 10, 600, 400), w_flag)) { + if (nk_tree_push(ctx, NK_TREE_NODE, "Standard", NK_MAXIMIZED)) { + nk_layout_row(ctx, NK_STATIC, 25, 2, ratio2); + for (int j = 0; j < 30; j++) { + if (sk_totals_sd[j] > 0) { + nk_label(ctx, skills[j], NK_TEXT_LEFT); + nk_property_int(ctx, "Total:", -10, &sk_totals_sd[j], 1000, 1, 1); + } + nk_layout_row_end(ctx); + } + } + nk_tree_pop(ctx); + if (nk_tree_push(ctx, NK_TREE_NODE, "Bonus", NK_MAXIMIZED)) { + nk_layout_row(ctx, NK_STATIC, 25, 2, ratio2); + for (int j = 0; j < 30; j++) { + if (sk_totals_bs[j] > 0) { + nk_label(ctx, skills[j], NK_TEXT_LEFT); + nk_property_int(ctx, "Total:", -10, &sk_totals_bs[j], 1000, 1, 1); + } + } + } + nk_tree_pop(ctx); + } + nk_end(ctx); +} + +void window(scale *s) { + GLFWwindow *win = 0x0; + int width = 0, height = 0; + struct nk_context ctx; + struct device device; + + win = init(&ctx, &device); + ctx.style.window.header.align = NK_HEADER_RIGHT; + while (!glfwWindowShouldClose(win)) { + handle_input(&ctx, win); + handle_window(s, &ctx); + glfwGetWindowSize(win, &width, &height); + glViewport(0, 0, width, height); + glClear(GL_COLOR_BUFFER_BIT); + glClearColor(0.2f, 0.2f, 0.2f, 1.0f); + device_draw(&device, &ctx, width, height, NK_ANTI_ALIASING_ON); + glfwSwapBuffers(win); + } + nk_free(&ctx); + device_shutdown(&device); + glfwTerminate(); + +} diff --git a/srcs/helpers.c b/srcs/helpers.c @@ -39,3 +39,137 @@ void print_trace(void) { free(strings); printf("\033[0m"); } + +scale_entry m_strcpy(yaml_token_t token) { + scale_entry res; + int i; + + if (token.data.scalar.length < 64) + res.buf = malloc(sizeof(char) * 64); + else + res.buf = malloc(sizeof(char) * 2024); + if (!res.buf) { + ERROR("Malloc error !\n"); + } + // If i use strcpy here, i get a weird bug on yaml_token_delete + // So, old school copy it is ! + for (i = 0; token.data.scalar.value[i]; i++) + res.buf[i] = token.data.scalar.value[i]; + res.buf[i] = 0x0; + res.len = token.data.scalar.length; + return res; +} + +void scale_debug(scale *res) { + printf("Name: %s\n", res->name.buf); + printf("Comment: %s\n", res->comment.buf); + printf("Intro: %s\n", res->intro.buf); + printf("Disclaimer: %s\n", res->disclaimer.buf); + printf("Guidelines: %s\n", res->guidelines.buf); + printf("Duration: %d\n", res->duration.val); + if (res->lang.val == LANG_EN) + printf("Lang: LANG_EU\n"); + else if (res->lang.val == LANG_FR) + printf("Lang: LANG_FR\n"); + else if (res->lang.val == LANG_RU) + printf("Lang: LANG_RU\n"); + printf("Correction num: %d\n", res->correction_n.val); + + for (scale_sections *it = res->sections; it; it = it->next) { + printf("SECTION: %s\n", it->name.buf); + for (scale_questions *it2 = it->questions; it2; it2 = it2->next) { + printf("\tQuestion: %s\n", it2->name.buf); + for (scale_skills *it3 = it2->skills; it3; it3 = it3->next) { + printf("\t\t%s : %d%%\n", it3->name.buf, it3->percent.val); + } + } + } +} + +int count_lines(char *s) { + int res, i; + + for (res = i = 0; s[i]; i++) { + if (s[i] == '\n') + res++; + } + if (res <= 5) + res = 7; + return res * 20; +} + +void add_section(scale_sections *s, char *name) { + scale_sections *res, *it; + + if (!strlen(name)) + return ; + res = malloc(sizeof(scale_sections)); + res->name.buf = malloc(sizeof(char) * strlen(name)); + res->description.buf = malloc(2024); + strcpy(res->name.buf, name); + strcpy(res->description.buf, ""); + res->description.len = 0; + res->questions = 0x0; + res->next = 0x0; + if (!s) { + s = res; + } else { + for (it = s; it->next; it = it->next); + it->next = res; + } +} + +void add_question(scale_sections *s, char *name, int j) { + scale_questions *res, *tmp; + scale_sections *it; + int z; + + if (!strlen(name)) + return ; + res = malloc(sizeof(scale_questions)); + res->name.buf = malloc(64); + res->guidelines.buf = malloc(1024); + strcpy(res->guidelines.buf, ""); + strcpy(res->name.buf, name); + res->skills = 0x0; + res->next = 0x0; + res->kind.val = 0; + res->rating.val = 0; + for (it = s, z = 0; it && z < j; it = it->next, z++); + if (!it) { + ERROR("Can't add question !\n"); + } + if (!it->questions) { + it->questions = res; + } else { + for (tmp = it->questions; tmp->next; tmp = tmp->next); + tmp->next = res; + } +} + +void add_skills(scale_questions *sk, int val, char *name) { + scale_skills *new, *it; + + if (!strlen(name)) + return ; + new = malloc(sizeof(scale_skills)); + new->percent.val = 0; + new->name.buf = malloc(strlen(name) + 1); + strcpy(new->name.buf, name); + new->name.val = val; + new->next = 0x0; + if (!sk->skills) { + sk->skills = new; + } else { + for (it = sk->skills; it->next; it = it->next) { + if (it->name.val == val) { + free(new->name.buf); + free(new); + return ; + } + } + if (it->name.val != val) { + it->next = new; + } + } +} diff --git a/srcs/main.c b/srcs/main.c @@ -1,8 +1,17 @@ # include <scale.h> int main(int ac, char **av) { - if (ac == 1 || !av) { + FILE *fd; + scale *s; + + if (ac == 1) { ERROR("Need an argument !\n"); } + fd = fopen(av[1], "r"); + if (!fd) { + ERROR("Failed to read file %s\n", av[1]); + } + s = read_scale(fd); + window(s); return 0; } diff --git a/srcs/yaml.c b/srcs/yaml.c @@ -7,6 +7,7 @@ void read_base_infos(yaml_parser_t *parser, scale *res) { token.type = YAML_STREAM_START_TOKEN; res->sections = 0x0; + res->is_primary.bol = true; while (token.type != YAML_STREAM_END_TOKEN) { if (!yaml_parser_scan(parser, &token)) { ERROR("YAML parser error ! Error value: (%d)", parser->error); @@ -17,7 +18,7 @@ void read_base_infos(yaml_parser_t *parser, scale *res) { cur = 2; } else if (token.type == YAML_SCALAR_TOKEN) { if (cur == 1) { - key = m_strcpy(token); + key = m_strcpy(token).buf; } else { if (!strcmp(key, "name")) res->name = m_strcpy(token); @@ -30,16 +31,18 @@ void read_base_infos(yaml_parser_t *parser, scale *res) { else if (!strcmp(key, "guidelines_md")) res->guidelines = m_strcpy(token); else if (!strcmp(key, "lang")) { - tmp = m_strcpy(token); + tmp = m_strcpy(token).buf; if (!strcmp(tmp, "en")) - res->lang = LANG_EN; + res->lang.val = LANG_EN; else if (!strcmp(tmp, "fr")) - res->lang = LANG_FR; + res->lang.val = LANG_FR; else if (!strcmp(tmp, "ru")) - res->lang = LANG_RU; + res->lang.val = LANG_RU; free(tmp); } else if (!strcmp(key, "correction_number")) { - res->correction_n = atoi((char *)token.data.scalar.value); + res->correction_n.val = atoi((char *)token.data.scalar.value); + } else if (!strcmp(key, "duration")) { + res->duration.val = atoi((char *)token.data.scalar.value); } free(key); key = 0x0; @@ -58,13 +61,17 @@ void read_base_infos(yaml_parser_t *parser, scale *res) { void read_skills(yaml_parser_t *parser, scale_questions *question) { yaml_token_t token; scale_skills *sk, *it; - int cur = 0, ct = 0; + int cur = 0, ct = 0, j; char *key = 0x0, *tmp = 0x0; + const char *skills[] = {"Adaptation & Creativity", "Algorithms & AI", "Company experience", "DB & Data", + "Functionnal programming", "Graphics", "Group & interpersonal", "Imperative programming", + "Network & system administration", "Object-oriented programming", + "Organization", "Parallel computing", "Rigor", "Security", "Technology integration", "Unix", "Web"}; + token.type = YAML_STREAM_START_TOKEN; sk = malloc(sizeof(scale_skills)); sk->next = 0x0; - (void)question; while (token.type != YAML_STREAM_END_TOKEN) { if (!yaml_parser_scan(parser, &token)) { ERROR("YAML parser error ! Error value: (%d)", parser->error); @@ -75,13 +82,15 @@ void read_skills(yaml_parser_t *parser, scale_questions *question) { cur = 2; } else if (token.type == YAML_SCALAR_TOKEN) { if (cur == 1) { - key = m_strcpy(token); + key = m_strcpy(token).buf; } else { if (!strcmp(key, "name")) { sk->name = m_strcpy(token); + for (j = 0; strcmp(sk->name.buf, skills[j]) && skills[j]; j++); + sk->name.val = j; } else if (!strcmp(key, "percentage")) { - tmp = m_strcpy(token); - sk->percent = atoi(tmp); + tmp = m_strcpy(token).buf; + sk->percent.val = atoi(tmp); free(tmp); } } @@ -112,6 +121,7 @@ void read_questions(yaml_parser_t *parser, scale_sections *sec) { question = malloc(sizeof(scale_questions)); question->next = 0x0; + question->skills = 0x0; token.type = YAML_STREAM_START_TOKEN; while (token.type != YAML_STREAM_END_TOKEN) { if (!yaml_parser_scan(parser, &token)) { @@ -123,7 +133,7 @@ void read_questions(yaml_parser_t *parser, scale_sections *sec) { cur = 2; } else if (token.type == YAML_SCALAR_TOKEN) { if (cur == 1) { - key = m_strcpy(token); + key = m_strcpy(token).buf; if (!strcmp(key, "questions_skills")) { read_skills(parser, question); if (!sec->questions) { @@ -134,6 +144,7 @@ void read_questions(yaml_parser_t *parser, scale_sections *sec) { } question = malloc(sizeof(scale_questions)); question->next = 0x0; + question->skills = 0x0; } } else { if (!strcmp(key, "name")) @@ -141,18 +152,18 @@ void read_questions(yaml_parser_t *parser, scale_sections *sec) { else if (!strcmp(key, "guidelines")) question->guidelines = m_strcpy(token); else if (!strcmp(key, "rating")) { - tmp = m_strcpy(token); + tmp = m_strcpy(token).buf; if (!strcmp(tmp, "bool")) - question->rating = R_BOOL; + question->rating.val = R_BOOL; else if (!strcmp(tmp, "multi")) - question->rating = R_MULTI; + question->rating.val = R_MULTI; free(tmp); } else if (!strcmp(key, "kind")) { - tmp = m_strcpy(token); + tmp = m_strcpy(token).buf; if (!strcmp(tmp, "standard")) - question->kind = R_STAND; + question->kind.val = R_STAND; else if (!strcmp(tmp, "bonus")) - question->kind = R_BONUS; + question->kind.val = R_BONUS; } free(key); } @@ -186,7 +197,7 @@ void read_sections(yaml_parser_t *parser, scale *res) { cur = 2; } else if (token.type == YAML_SCALAR_TOKEN) { if (cur == 1) { - key = m_strcpy(token); + key = m_strcpy(token).buf; if (!strcmp(key, "questions")) { read_questions(parser, sec); if (!res->sections) { @@ -229,7 +240,7 @@ scale *read_scale(FILE *fd) { } read_base_infos(&parser, res); read_sections(&parser, res); - scale_debug(res); + /*scale_debug(res);*/ yaml_parser_delete(&parser); fclose(fd); return res;