nuclear@0: #include nuclear@1: #include nuclear@0: #include nuclear@0: #ifndef __APPLE__ nuclear@0: #include nuclear@0: #else nuclear@0: #include nuclear@0: #endif nuclear@0: #include "imtk.h" nuclear@0: nuclear@1: #define CHECKBOX_SIZE 14 nuclear@1: nuclear@1: enum { nuclear@1: FRAME_OUTSET, nuclear@1: FRAME_INSET nuclear@1: }; nuclear@1: nuclear@1: /* default colors, can be changed with imtk_set_color */ nuclear@1: static float colors[][4] = { nuclear@1: {0.0, 0.0, 0.0}, /* text color */ nuclear@1: {0.7, 0.7, 0.7}, /* base color */ nuclear@1: {0.85, 0.85, 0.85}, /* focus color */ nuclear@1: {1.0, 1.0, 1.0}, /* lit bevel */ nuclear@1: {0.3, 0.3, 0.3} /* shadowed bevel */ nuclear@1: }; nuclear@1: nuclear@0: static int scr_width = 1, scr_height = 1; nuclear@0: static int mousex, mousey, mouse_bnmask; nuclear@0: static int active = -1, hot = -1; nuclear@0: nuclear@0: static void set_active(int id); nuclear@0: static int set_hot(int id); nuclear@0: static int hit_test(int x, int y, int w, int h); nuclear@0: nuclear@1: static void draw_button(int id, const char *label, int x, int y); nuclear@0: static void calc_button_size(const char *label, int *wret, int *hret); nuclear@1: static void draw_checkbox(int id, const char *label, int x, int y, int state); nuclear@0: static void draw_string(int x, int y, const char *str); nuclear@0: static int string_size(const char *str); nuclear@1: static void draw_frame(int x, int y, int w, int h, int style); nuclear@1: nuclear@1: void imtk_set_color(int col, float r, float g, float b) nuclear@1: { nuclear@1: assert(col >= 0 && col < sizeof colors / sizeof *colors); nuclear@1: nuclear@1: colors[col][0] = r; nuclear@1: colors[col][1] = g; nuclear@1: colors[col][2] = b; nuclear@1: } nuclear@0: nuclear@0: void imtk_inp_key(int key, int state) nuclear@0: { nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: nuclear@0: void imtk_inp_mouse(int bn, int state) nuclear@0: { nuclear@0: if(state == IMTK_DOWN) { nuclear@0: mouse_bnmask |= 1 << bn; nuclear@0: } else { nuclear@0: mouse_bnmask &= ~(1 << bn); nuclear@0: } nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: nuclear@0: void imtk_inp_motion(int x, int y) nuclear@0: { nuclear@0: mousex = x; nuclear@0: mousey = y; nuclear@0: nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: nuclear@0: void imtk_inp_reshape(int x, int y) nuclear@0: { nuclear@0: scr_width = x; nuclear@0: scr_height = y; nuclear@0: } nuclear@0: nuclear@0: void imtk_begin(void) nuclear@0: { nuclear@0: glMatrixMode(GL_PROJECTION); nuclear@0: glPushMatrix(); nuclear@0: glLoadIdentity(); nuclear@0: glTranslatef(-1, 1, 0); nuclear@0: glScalef(2.0 / scr_width, -2.0 / scr_height, 1.0); nuclear@0: } nuclear@0: nuclear@0: void imtk_end(void) nuclear@0: { nuclear@0: glMatrixMode(GL_PROJECTION); nuclear@0: glPopMatrix(); nuclear@0: } nuclear@0: nuclear@0: int imtk_button(int id, const char *label, int x, int y) nuclear@0: { nuclear@0: int w, h, res = 0; nuclear@0: int over = 0; nuclear@0: nuclear@0: assert(id >= 0); nuclear@0: nuclear@0: calc_button_size(label, &w, &h); nuclear@0: nuclear@0: if(hit_test(x, y, w, h)) { nuclear@1: set_hot(id); nuclear@0: over = 1; nuclear@0: } nuclear@0: nuclear@0: if(mouse_bnmask & (1 << IMTK_LEFT_BUTTON)) { nuclear@0: if(over) { nuclear@0: set_active(id); nuclear@0: } nuclear@0: } else { /* mouse button up */ nuclear@0: if(active == id) { nuclear@0: set_active(-1); nuclear@0: if(hot == id && over) { nuclear@0: res = 1; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@1: draw_button(id, label, x, y); nuclear@0: return res; nuclear@0: } nuclear@0: nuclear@1: int imtk_checkbox(int id, const char *label, int x, int y, int state) nuclear@1: { nuclear@1: int sz = CHECKBOX_SIZE; nuclear@1: int over = 0; nuclear@1: nuclear@1: assert(id >= 0); nuclear@1: nuclear@1: if(hit_test(x, y, sz, sz)) { nuclear@1: set_hot(id); nuclear@1: over = 1; nuclear@1: } nuclear@1: nuclear@1: if(mouse_bnmask & (1 << IMTK_LEFT_BUTTON)) { nuclear@1: if(over) { nuclear@1: set_active(id); nuclear@1: } nuclear@1: } else { /* mouse button up */ nuclear@1: if(active == id) { nuclear@1: set_active(-1); nuclear@1: if(hot == id && over) { nuclear@1: state = !state; nuclear@1: } nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: draw_checkbox(id, label, x, y, state); nuclear@1: return state; nuclear@1: } nuclear@1: nuclear@0: static void set_active(int id) nuclear@0: { nuclear@0: active = id; nuclear@0: } nuclear@0: nuclear@0: static int set_hot(int id) nuclear@0: { nuclear@0: if(active == -1) { nuclear@0: hot = id; nuclear@0: return 1; nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: static int hit_test(int x, int y, int w, int h) nuclear@0: { nuclear@0: return mousex >= x && mousex < (x + w) && nuclear@0: mousey >= y && mousey < (y + h); nuclear@0: } nuclear@0: nuclear@1: static void draw_button(int id, const char *label, int x, int y) nuclear@0: { nuclear@0: int width, height; nuclear@0: nuclear@0: calc_button_size(label, &width, &height); nuclear@0: nuclear@0: glBegin(GL_QUADS); nuclear@1: if(hit_test(x, y, width, height)) { nuclear@1: glColor3fv(colors[IMTK_FOCUS_COLOR]); nuclear@0: } else { nuclear@1: glColor3fv(colors[IMTK_BASE_COLOR]); nuclear@0: } nuclear@0: glVertex2f(x, y); nuclear@0: glVertex2f(x + width, y); nuclear@0: glVertex2f(x + width, y + height); nuclear@0: glVertex2f(x, y + height); nuclear@0: glEnd(); nuclear@0: nuclear@1: draw_frame(x, y, width, height, active == id ? FRAME_INSET : FRAME_OUTSET); nuclear@1: nuclear@1: glColor3fv(colors[IMTK_TEXT_COLOR]); nuclear@0: draw_string(x + 20, y + 15, label); nuclear@0: } nuclear@0: nuclear@0: static void calc_button_size(const char *label, int *wret, int *hret) nuclear@0: { nuclear@0: int strsz = string_size(label); nuclear@0: if(wret) *wret = strsz + 40; nuclear@0: if(hret) *hret = 20; nuclear@0: } nuclear@0: nuclear@1: static void draw_checkbox(int id, const char *label, int x, int y, int state) nuclear@1: { nuclear@1: static const int sz = CHECKBOX_SIZE; nuclear@1: nuclear@1: if(hit_test(x, y, sz, sz)) { nuclear@1: glColor3fv(colors[IMTK_FOCUS_COLOR]); nuclear@1: } else { nuclear@1: glColor3fv(colors[IMTK_BASE_COLOR]); nuclear@1: } nuclear@1: nuclear@1: glBegin(GL_QUADS); nuclear@1: glVertex2f(x, y); nuclear@1: glVertex2f(x + sz, y); nuclear@1: glVertex2f(x + sz, y + sz); nuclear@1: glVertex2f(x, y + sz); nuclear@1: glEnd(); nuclear@1: nuclear@1: draw_frame(x, y, sz, sz, FRAME_INSET); nuclear@1: nuclear@1: glColor3fv(colors[IMTK_TEXT_COLOR]); nuclear@1: if(state) { nuclear@1: glPushAttrib(GL_LINE_BIT); nuclear@1: glLineWidth(2); nuclear@1: nuclear@1: glBegin(GL_LINES); nuclear@1: glVertex2f(x + 2, y + 2); nuclear@1: glVertex2f(x + sz - 2, y + sz - 2); nuclear@1: glVertex2f(x + sz - 2, y + 2); nuclear@1: glVertex2f(x + 2, y + sz - 2); nuclear@1: glEnd(); nuclear@1: nuclear@1: glPopAttrib(); nuclear@1: } nuclear@1: nuclear@1: draw_string(x + sz + 5, y + sz - 2, label); nuclear@1: } nuclear@1: nuclear@0: static void draw_string(int x, int y, const char *str) nuclear@0: { nuclear@0: glRasterPos2i(x, y); nuclear@0: while(*str) { nuclear@1: glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *str++); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: static int string_size(const char *str) nuclear@0: { nuclear@1: return glutBitmapLength(GLUT_BITMAP_HELVETICA_12, (const unsigned char*)str); nuclear@0: } nuclear@1: nuclear@1: static void draw_frame(int x, int y, int w, int h, int style) nuclear@1: { nuclear@1: float tcol[3], bcol[3]; nuclear@1: nuclear@1: switch(style) { nuclear@1: case FRAME_INSET: nuclear@1: memcpy(tcol, colors[IMTK_BEVEL_SHAD_COLOR], sizeof tcol); nuclear@1: memcpy(bcol, colors[IMTK_BEVEL_LIT_COLOR], sizeof bcol); nuclear@1: break; nuclear@1: nuclear@1: case FRAME_OUTSET: nuclear@1: default: nuclear@1: memcpy(tcol, colors[IMTK_BEVEL_LIT_COLOR], sizeof tcol); nuclear@1: memcpy(bcol, colors[IMTK_BEVEL_SHAD_COLOR], sizeof bcol); nuclear@1: } nuclear@1: nuclear@1: glBegin(GL_LINES); nuclear@1: glColor3fv(tcol); nuclear@1: glVertex2f(x, y + h); nuclear@1: glVertex2f(x, y); nuclear@1: glVertex2f(x, y); nuclear@1: glVertex2f(x + w, y); nuclear@1: glColor3fv(bcol); nuclear@1: glVertex2f(x + w, y); nuclear@1: glVertex2f(x + w, y + h); nuclear@1: glVertex2f(x + w, y + h); nuclear@1: glVertex2f(x, y + h); nuclear@1: glEnd(); nuclear@1: }