/* * GRacer * * Copyright (C) 1999 Takashi Matsuda * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #include #include #include #include #include #include #include "glutwidgets.h" #include "glbind.h" #include "sound.h" static void default_label_display (GlutObject); static void default_button_display (GlutObject); static void default_button_keyboard (GlutObject, unsigned char, int, int); static void default_button_mouse (GlutObject, int, int, int, int); static void default_entry_display (GlutObject); static void default_entry_keyboard (GlutObject, unsigned char, int, int); static void default_entry_mouse (GlutObject, int, int, int, int); static int glut_widget_check_bbox (GlutObject obj, int x, int y); static void glut_widget_calc_bbox (GlutObject); static int glut_widget_state (GlutObject); static void glut_bitmap_string (void *font, char *string, int length); GrSList *glut_objects; GlutObject grab_widget; GlutObject focus_widget; GLuint widget_dl; int widget_changed; int screen_width = 300; int screen_height = 300; static GLfloat default_fg_color[GR_NUM_STATE][4] = { {0.7, 0.7, 1, 1}, {0.7, 0.7, 1, 1}, {0.5, 0.5, 0.8, 1}, {1, 1, 0, 1}, }; static GLfloat default_bg_color[GR_NUM_STATE][4] = { {0.6, 0.6, 0.6, 1}, {0.8, 0.8, 1.0, 1}, {0.8, 0.8, 1.0, 1}, {0.8, 0.8, 1.0, 1}, }; GlutFontInfo bitmap_font_infos[] = { {GLUT_BITMAP_8_BY_13, 13, 11, 2}, {GLUT_BITMAP_9_BY_15, 15, 13, 2}, {GLUT_BITMAP_TIMES_ROMAN_10, 10, 7, 3}, {GLUT_BITMAP_TIMES_ROMAN_24, 24, 18, 6}, {GLUT_BITMAP_HELVETICA_10, 10, 8, 2}, {GLUT_BITMAP_HELVETICA_12, 12, 9, 3}, {GLUT_BITMAP_HELVETICA_18, 18, 15, 3}, {NULL, -1, 0, 0}, }; void glut_post_redisplay (void) { widget_changed = 1; glutPostRedisplay (); } void glut_forget_all (void) { GlutRoot *root; while (glut_objects) { root = glut_objects->data; gr_DECREF (root); glut_objects = gr_slist_remove (glut_objects); } grab_widget = NULL; focus_widget = NULL; } GlutFontInfo * glut_get_bitmap_font_info (void *font) { int i; for (i=0; bitmap_font_infos[i].height > 0; i++) { if (font == bitmap_font_infos[i].font) { return bitmap_font_infos + i; } } return NULL; } void glut_append_object (GlutObject object) { GlutWidget *widget = object; glut_objects = gr_slist_append (glut_objects, object); if (!focus_widget) { glut_widget_set_focus (widget); } glut_post_redisplay (); } void glut_prepend_object (GlutObject object) { GlutWidget *widget = object; glut_objects = gr_slist_prepend (glut_objects, object); if (!focus_widget) { glut_widget_set_focus (widget); } glut_post_redisplay (); } void glut_insert_object (GlutObject object, GlutObject after) { GrSList *list; GlutWidget *widget = object; if (!after) { glut_prepend_object (object); return; } for (list=glut_objects; list!=NULL; list=list->next) { if (list->data == after) { list->next = gr_slist_prepend (list->next, object); if (!focus_widget) { glut_widget_set_focus (widget); } return; } } /* after not found */ glut_prepend_object (object); glut_post_redisplay (); } void glut_remove_object (GlutObject object) { GrSList *list; if (!glut_objects) return; if (focus_widget == object) focus_widget = NULL; if (grab_widget == object) grab_widget = NULL; if (glut_objects->data == object) { glut_objects = gr_slist_remove (glut_objects); } else { list = glut_objects; while (list->next) { if (list->next->data == object) { list->next = gr_slist_remove (list->next); break; } list = list->next; } } glut_post_redisplay (); } void glut_display_func (void) { GrSList *list; GlutRoot *root; GL_CHECK(glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); GL_CHECK(glEnable (GL_CULL_FACE)); GL_CHECK(glEnable (GL_COLOR_MATERIAL)); GL_CHECK(glEnable (GL_LIGHTING)); GL_CHECK(glEnable (GL_LIGHT0)); GL_CHECK(glEnable (GL_DEPTH_TEST)); if (glut_objects) { GL_CHECK(glMatrixMode (GL_PROJECTION)); GL_CHECK(glLoadIdentity ()); GL_CHECK(glOrtho (-screen_width/2, screen_width/2, -screen_height/2, screen_height/2, -10, 10)); GL_CHECK(glMatrixMode (GL_MODELVIEW)); GL_CHECK(glLoadIdentity ()); } list = glut_objects; gr_FOREACH (list, root) { if (root->display_func) { (*root->display_func) (root); } } tcl_DisplayFunc (); glutSwapBuffers (); gr_sound_update (); } void glut_reshape_func (int width, int height) { GrSList *list; GlutRoot *root; GlutWidget *widget; list = glut_objects; gr_FOREACH (list, widget) { if (widget->core.type == GR_GLUT_ROOT_WIDGET) { switch (widget->anchor & GR_HORIZONTAL_MASK) { case GR_LEFT: widget->x -= (width - screen_width) / 2; break; case GR_RIGHT: widget->x += (width - screen_width) / 2; break; case GR_LEFT|GR_RIGHT: widget->x -= (width - screen_width) / 2; widget->width += (width - screen_width); break; } switch (widget->anchor & GR_VERTICAL_MASK) { case GR_BOTTOM: widget->y -= (height - screen_height) / 2; break; case GR_TOP: widget->y += (height - screen_height) / 2; break; case GR_LEFT|GR_RIGHT: widget->y -= (height - screen_height) / 2; widget->height += (width - screen_height); break; } glut_widget_calc_bbox (widget); } } screen_width = width; screen_height = height; list = glut_objects; gr_FOREACH (list, root) { if (root->reshape_func) { (*root->reshape_func) (root, width, height); } } tcl_ReshapeFunc (width, height); glutPostRedisplay (); } void glut_keyboard_func (unsigned char key, int x, int y) { GrSList *list; GlutWidget *widget; int done = 0; int modifiers; int wx, wy; wx = x - screen_width / 2; wy = screen_height / 2 - y; if (focus_widget) { widget = focus_widget; (widget->keyboard_func) (widget, key, wx, wy); done = 1; } else { list = glut_objects; gr_FOREACH (list, widget) { if (glut_widget_check_bbox (widget, wx, wy)) { if (widget->keyboard_func) { (*widget->keyboard_func) (widget, key, wx, wy); done = 1; } } } } if (!done) { switch (key) { case '\t': modifiers = glutGetModifiers (); if (modifiers) { glut_widget_set_focus (glut_previous_focus_widget (NULL)); } else { glut_widget_set_focus (glut_next_focus_widget (NULL)); } break; } } tcl_KeyboardFunc (key, x, y); } static GlutObject find_left_focusable_widget (GlutObject obj) { GlutWidget *widget = obj; GlutWidget *w; GlutWidget *candidate = NULL; GrSList *list; int distance = 0, new_distance; if (!glut_widget_is_focusable (widget)) return glut_next_focus_widget (NULL); list = glut_objects; gr_FOREACH (list, w) { if (!glut_widget_is_focusable (w)) continue; if (!(widget->x0 >= w->x1)) continue; new_distance = fabs (w->x1 - widget->x0) + fabs (w->y0 - widget->y0) * 5; if (candidate == NULL || distance > new_distance) { candidate = w; distance = new_distance; } } return candidate; } static GlutObject find_right_focusable_widget (GlutObject obj) { GlutWidget *widget = obj; GlutWidget *w; GlutWidget *candidate = NULL; GrSList *list; int distance = 0, new_distance; if (!glut_widget_is_focusable (widget)) return glut_next_focus_widget (NULL); list = glut_objects; gr_FOREACH (list, w) { if (!glut_widget_is_focusable (w)) continue; if (!(widget->x1 <= w->x0)) continue; new_distance = fabs (w->x0 - widget->x1) + fabs (w->y0 - widget->y0) * 5; if (candidate == NULL || distance > new_distance) { candidate = w; distance = new_distance; } } return candidate; } static GlutObject find_upper_focusable_widget (GlutObject obj) { GlutWidget *widget = obj; GlutWidget *w; GlutWidget *candidate = NULL; GrSList *list; int distance = 0, new_distance; if (!glut_widget_is_focusable (widget)) return glut_next_focus_widget (NULL); list = glut_objects; gr_FOREACH (list, w) { if (!glut_widget_is_focusable (w)) continue; if (!(widget->y1 <= w->y0)) continue; new_distance = fabs (w->x0 - widget->x0) * 2 + fabs (w->y0 - widget->y1); if (candidate == NULL || distance > new_distance) { candidate = w; distance = new_distance; } } return candidate; } static GlutObject find_lower_focusable_widget (GlutObject obj) { GlutWidget *widget = obj; GlutWidget *w; GlutWidget *candidate = NULL; GrSList *list; int distance = 0, new_distance; if (!glut_widget_is_focusable (widget)) return glut_next_focus_widget (NULL); list = glut_objects; gr_FOREACH (list, w) { if (!glut_widget_is_focusable (w)) continue; if (!(widget->y0 >= w->y1)) continue; new_distance = fabs (w->x0 - widget->x0) * 2 + fabs (w->y1 - widget->y0); if (candidate == NULL || distance > new_distance) { candidate = w; distance = new_distance; } } return candidate; } void glut_special_func (int key, int x, int y) { GrSList *list; GlutWidget *widget; int done = 0; int wx, wy; wx = x - screen_width / 2; wy = screen_height / 2 - y; if (focus_widget) { widget = focus_widget; if (widget->special_func) { (widget->special_func) (widget, key, wx, wy); done = 1; } } else { list = glut_objects; gr_FOREACH (list, widget) { if (glut_widget_check_bbox (widget, wx, wy)) { if (widget->special_func) { (*widget->special_func) (widget, key, wx, wy); done = 1; } } } } if (!done) { switch (key) { case GLUT_KEY_LEFT: if ((widget = find_left_focusable_widget (focus_widget))) { glut_widget_set_focus (widget); } break; case GLUT_KEY_RIGHT: if ((widget = find_right_focusable_widget (focus_widget))) { glut_widget_set_focus (widget); } break; case GLUT_KEY_UP: if ((widget = find_upper_focusable_widget (focus_widget))) { glut_widget_set_focus (widget); } break; case GLUT_KEY_DOWN: if ((widget = find_lower_focusable_widget (focus_widget))) { glut_widget_set_focus (widget); } break; } } tcl_SpecialFunc (key, x, y); } void glut_mouse_func (int button, int state, int x, int y) { GrSList *list; GlutWidget *widget; int wx, wy; wx = x - screen_width / 2; wy = screen_height / 2 - y; if (state == GLUT_DOWN) grab_widget = NULL; list = glut_objects; gr_FOREACH (list, widget) { if (glut_widget_check_bbox (widget, wx, wy)) { if (widget->mouse_func) { (*widget->mouse_func) (widget, button, state, wx, wy); } } } if (state == GLUT_UP) grab_widget = NULL; tcl_MouseFunc (button, state, x, y); } void glut_passive_motion_func (int x, int y) { GrSList *list; GlutWidget *widget; int redraw = 0; int wx, wy; wx = x - screen_width / 2; wy = screen_height / 2 - y; list = glut_objects; gr_FOREACH (list, widget) { if (widget->core.type != GR_GLUT_ROOT_WIDGET) continue; if (glut_widget_check_bbox (widget, wx, wy)) { if (!widget->active) { redraw = 1; widget->active = 1; } } else { if (widget->active) { redraw = 1; widget->active = 0; } } } if (redraw) { glut_post_redisplay (); } tcl_PassiveMotionFunc (x, y); } int glut_bitmap_string_width (void *font, char *string, int length) { int i; int width = 0; if (!string) return 0; for (i=0; idl = glGenLists (128); } } void glut_root_destroy (GlutObject obj) { GlutRoot *root = obj; glDeleteLists (root->dl, 1); free (root); } void glut_root_init (GlutObject obj) { static int do_init = 1; GlutRoot *root = obj; if (do_init) { glut_widgets_initialize (); do_init = 0; } gr_FREE_FUNC (obj, glut_root_destroy); GL_CHECK(root->dl = glGenLists (1)); root->changed = 1; root->type = GR_GLUT_ROOT; } GlutObject glut_root_new (void) { GlutRoot *root; root = gr_new0 (GlutRoot, 1); glut_root_init (root); return root; } void glut_widget_destroy (GlutObject obj) { GlutWidget *widget = obj; glut_root_destroy ((GlutRoot *) widget); } void glut_widget_init (GlutObject obj) { GlutWidget *widget = obj; glut_root_init (&widget->core); gr_FREE_FUNC (obj, glut_root_destroy); widget->core.type = GR_GLUT_ROOT_WIDGET; widget->font = GLUT_BITMAP_HELVETICA_18; memcpy (widget->fg_color, default_fg_color, sizeof (default_fg_color)); memcpy (widget->bg_color, default_bg_color, sizeof (default_bg_color)); } GlutObject glut_widget_new (void) { GlutWidget *widget; widget = gr_new0 (GlutWidget, 1); glut_widget_init (widget); return widget; } static void glut_widget_calc_bbox (GlutObject obj) { GlutWidget *widget = obj; switch (widget->anchor & GR_HORIZONTAL_MASK) { case GR_CENTER: widget->x0 = widget->x - widget->width / 2; widget->x1 = widget->x + widget->width / 2; break; default: case GR_LEFT: widget->x0 = widget->x; widget->x1 = widget->x + widget->width; break; case GR_RIGHT: widget->x0 = widget->x - widget->width; widget->x1 = widget->x; break; } switch (widget->anchor & GR_VERTICAL_MASK) { case GR_CENTER: widget->y0 = widget->y - widget->height / 2; widget->y1 = widget->y + widget->height / 2; break; default: case GR_TOP: widget->y0 = widget->y - widget->height; widget->y1 = widget->y; break; case GR_BOTTOM: widget->y0 = widget->y; widget->y1 = widget->y + widget->height; break; } } static int glut_widget_check_bbox (GlutObject obj, int x, int y) { GlutWidget *widget = obj; if (widget->core.type != GR_GLUT_ROOT_WIDGET) return 0; return (x >= widget->x0 && y >= widget->y0 && x <= widget->x1 && y <= widget->y1); } static void glut_widget_check_size (GlutObject obj) { GlutWidget *widget = obj; if (widget->check_size) { (*widget->check_size) (obj); } glut_widget_calc_bbox (obj); } void glut_widget_set_position (GlutObject obj, int x, int y, int anchor) { GlutWidget *widget = obj; switch (anchor & GR_HORIZONTAL_MASK) { case GR_LEFT|GR_RIGHT: case GR_LEFT: widget->x = -screen_width / 2 + x; break; case GR_RIGHT: widget->x = screen_width / 2 + x; break; default: widget->x = x; } switch (anchor & GR_VERTICAL_MASK) { case GR_BOTTOM|GR_TOP: case GR_BOTTOM: widget->y = -screen_height / 2 + y; break; case GR_TOP: widget->y = screen_height / 2 + y; break; default: widget->y = y; } widget->anchor = anchor; glut_widget_check_size (obj); } void glut_widget_set_size (GlutObject obj, int width, int height) { GlutWidget *widget = obj; widget->width = width; widget->height = height; glut_widget_check_size (obj); } void glut_widget_move (GlutObject obj, int dx, int dy) { GlutWidget *widget = obj; widget->x += dx; widget->y += dy; glut_widget_calc_bbox (obj); glut_post_redisplay (); } void glut_widget_set_font (GlutObject obj, void *font) { GlutWidget *widget = obj; widget->font = font; glut_widget_check_size (obj); } int glut_widget_is_focusable (GlutObject obj) { GlutWidget *widget = obj; return (widget && widget->core.type == GR_GLUT_ROOT_WIDGET && (widget->keyboard_func || widget->special_func)); } void glut_widget_set_focus (GlutObject obj) { GlutWidget *widget = obj; if (!obj) { return; } if (!glut_widget_is_focusable (widget)) return; if (focus_widget != widget) { focus_widget = widget; glut_post_redisplay (); } } static int glut_widget_state (GlutObject obj) { GlutWidget *widget = obj; if (grab_widget == obj) return GR_STATE_GRAB; if (focus_widget == obj) return GR_STATE_FOCUS; if (widget->active) return GR_STATE_ACTIVE; return GR_STATE_NORMAL; } static int glut_label_width (GlutObject obj) { GlutLabel *label = obj; int i, j, width = 0, new_width; for (i=0; ilength; i++) { for (j=i; jlength && label->title[j] != '\n'; j++) {} new_width = glut_bitmap_string_width (label->core.font, label->title + i, j - i); if (new_width > width) width = new_width; i = j + 1; } return width; } static void glut_label_check_size (GlutObject obj) { GlutWidget *widget = obj; GlutLabel *label = obj; int width; GlutFontInfo *finfo; width = glut_label_width (obj); finfo = glut_get_bitmap_font_info (widget->font); widget->width = width; label->str_width = width; if (widget->height < finfo->height) { widget->height = finfo->height; } } void glut_label_destroy (GlutObject obj) { GlutLabel *label = obj; free (label->title); glut_widget_destroy (obj); } void glut_label_init (GlutObject obj) { GlutLabel *label = obj; glut_widget_init (&label->core); gr_FREE_FUNC (label, glut_label_destroy); label->core.type = GR_GLUT_WIDGET_LABEL; label->core.core.display_func = default_label_display; label->core.check_size = glut_label_check_size; label->justify = -1; } GlutObject glut_label_new (void) { GlutLabel *label; label = gr_new0 (GlutLabel, 1); glut_label_init (label); return label; } void glut_label_set_text (GlutObject obj, char *text) { GlutLabel *label = obj; if (label->title) free (label->title); label->title = NULL; if (!text) { label->length = 0; } else { label->length = strlen (text); label->title = strdup (text); } glut_widget_check_size (obj); } void glut_button_check_size (GlutObject obj) { GlutWidget *widget = obj; GlutButton *button = obj; int width; GlutFontInfo *finfo; width = glut_bitmap_string_width (widget->font, button->title, button->length); button->str_width = width; if (widget->width < width + 10) { widget->width = width + 10; } finfo = glut_get_bitmap_font_info (widget->font); if (widget->height < finfo->height + 4) { widget->height = finfo->height + 4; } } void glut_button_destroy (GlutObject obj) { GlutButton *button = obj; free (button->title); glut_widget_destroy (obj); } void glut_button_init (GlutObject obj) { GlutButton *button = obj; glut_widget_init (&button->core); button->core.type = GR_GLUT_WIDGET_BUTTON; gr_FREE_FUNC (button, glut_button_destroy); button->core.core.display_func = default_button_display; button->core.keyboard_func = default_button_keyboard; button->core.mouse_func = default_button_mouse; button->core.check_size = glut_button_check_size; } GlutObject glut_button_new (void) { GlutButton *button; button = gr_new0 (GlutButton, 1); glut_button_init (button); return button; } void glut_button_set_text (GlutObject obj, char *text) { GlutButton *button = obj; if (button->title) { free (button->title); button->title = NULL; } if (!text) { button->length = 0; } else { button->length = strlen (text); button->title = strdup (text); } glut_widget_check_size (obj); } void glut_entry_check_size (GlutObject obj) { GlutWidget *widget = obj; GlutFontInfo *finfo; finfo = glut_get_bitmap_font_info (widget->font); if (widget->height < finfo->height + finfo->descent) { widget->height = finfo->height + finfo->descent; } } static void button_timer_func (int value) { GlutButton *button = grab_widget; if (!button || button->core.core.type != GR_GLUT_ROOT_WIDGET || button->core.type != GR_GLUT_WIDGET_BUTTON) return; if (button->invoke_func) { (*button->invoke_func) (button); } grab_widget = NULL; glut_post_redisplay (); } void glut_button_invoke (GlutObject obj) { GlutButton *button = obj; if (button->invoke_func) { grab_widget = obj; glut_post_redisplay (); glutTimerFunc (200, button_timer_func, 0); } } void glut_entry_destroy (GlutObject obj) { glut_widget_destroy (obj); } void glut_entry_init (GlutObject obj) { GlutEntry *entry = obj; glut_widget_init (&entry->core); entry->core.type = GR_GLUT_WIDGET_ENTRY; gr_FREE_FUNC (entry, glut_entry_destroy); entry->core.core.display_func = default_entry_display; entry->core.keyboard_func = default_entry_keyboard; entry->core.mouse_func = default_entry_mouse; entry->core.check_size = glut_entry_check_size; } GlutObject glut_entry_new (void) { GlutEntry *entry; entry = gr_new0 (GlutEntry, 1); glut_entry_init (entry); return entry; } void glut_entry_set_text (GlutObject obj, char *text) { GlutEntry *entry = obj; int length; if (!text) { entry->length = 0; entry->display_pos = 0; entry->calet_pos = 0; } else { length = strlen (text); if (length > 1024) length = 1024; entry->length = length; strncpy (entry->text, text, length); entry->display_pos = 0; if (entry->calet_pos > entry->length) { entry->calet_pos = entry->length; } } glut_widget_check_size (obj); } void glut_entry_invoke (GlutObject obj) { GlutEntry *entry = obj; if (entry->invoke_func) { (*entry->invoke_func) (entry); } } GlutObject glut_last_object (void) { GrSList *list; if (!glut_objects) return NULL; for (list=glut_objects;list->next!=NULL; list=list->next) {} return list->data; } GlutObject glut_previous_object (GlutObject from) { GrSList *list; if (!glut_objects) return NULL; if (glut_objects->data == from) { return glut_last_object (); } else { for (list=glut_objects; list->next && list->next->data != from; list=list->next) {} if (list) { return list->data; } else { return NULL; } } } GlutObject glut_next_object (GlutObject from) { GrSList *list; if (!glut_objects) return NULL; for (list=glut_objects; list!=NULL; list=list->next) { if (list->data == from) break; } if (list && list->next) { return list->next->data; } else { return glut_objects->data; } } GlutObject glut_previous_focus_widget (GlutObject current) { GrSList *list; GlutWidget *widget; GlutObject candidate = NULL; if (!current) { for (list=glut_objects; list!=NULL; list=list->next) { widget = list->data; if (glut_widget_is_focusable (widget)) { candidate = widget; } } return candidate; } else { widget = current; do { widget = glut_previous_object (widget); } while (!(widget == current || glut_widget_is_focusable (widget))); return widget; } } GlutObject glut_next_focus_widget (GlutObject current) { GrSList *list; GlutWidget *widget; if (!current) { for (list=glut_objects; list!=NULL; list=list->next) { widget = list->data; if (glut_widget_is_focusable (widget)) { break; } } return (list)? list->data : NULL; } else { widget = current; do { widget = glut_next_object (widget); } while (!(widget == current || glut_widget_is_focusable (widget))); return widget; } } static void default_button_display (GlutObject obj) { GlutWidget *widget = obj; GlutButton *button = obj; int x, y; int dx, dy; int state; GlutFontInfo *finfo; state = glut_widget_state (obj); if (grab_widget == widget) { dx = dy = 2; } else { dx = dy = 0; } finfo = glut_get_bitmap_font_info (widget->font); glColor4fv (widget->bg_color[state]); glRecti (widget->x0+dx, widget->y0-dy, widget->x1+dx, widget->y1-dy); if (button->length > 0) { x = widget->x0 + (widget->width - button->str_width) / 2 + dx; y = widget->y0 + (widget->height - finfo->height) / 2 + finfo->descent -dy; glColor4f (widget->bg_color[state][0] * 0.8, widget->bg_color[state][1] * 0.8, widget->bg_color[state][2] * 0.8, widget->bg_color[state][3]); glRasterPos3i (x+2, y-2, 1); glut_bitmap_string (widget->font, button->title, button->length); glColor4fv (widget->fg_color[state]); glRasterPos3i (x, y, 2); glut_bitmap_string (widget->font, button->title, button->length); } glColor4f (widget->bg_color[state][0] * 0.6, widget->bg_color[state][1] * 0.6, widget->bg_color[state][2] * 0.6, widget->bg_color[state][3]); glRecti (widget->x0+4, widget->y0-4, widget->x1+4, widget->y1-4); } static void default_button_keyboard (GlutObject obj, unsigned char key, int x, int y) { int modifiers; switch (key) { case ' ': case '\r': glut_button_invoke (obj); break; case '\t': modifiers = glutGetModifiers (); if (modifiers) { focus_widget = glut_previous_focus_widget (focus_widget); } else { focus_widget = glut_next_focus_widget (focus_widget); } glut_post_redisplay (); break; } } static void default_button_mouse (GlutObject obj, int button, int state, int x, int y) { GlutButton *b = obj; if (state == GLUT_DOWN) { grab_widget = obj; focus_widget = obj; glut_post_redisplay (); } else { if (b->invoke_func && grab_widget == b) { (*b->invoke_func) (obj); } grab_widget = NULL; glut_post_redisplay (); } } static void default_entry_display (GlutObject obj) { GlutWidget *widget = obj; GlutEntry *entry = obj; int width; GlutFontInfo *finfo; int state; int calet_width; int x, y; int i; state = glut_widget_state (obj); glColor4fv (widget->bg_color[state]); glBegin (GL_LINE_LOOP); glVertex3i (widget->x0, widget->y0, 2); glVertex3i (widget->x1, widget->y0, 2); glVertex3i (widget->x1, widget->y1, 2); glVertex3i (widget->x0, widget->y1, 2); glEnd (); if (entry->calet_pos < entry->display_pos) { entry->display_pos = entry->calet_pos; } width = glut_bitmap_string_width (widget->font, entry->text + entry->display_pos, entry->calet_pos - entry->display_pos); if (width > widget->width - 10) { width -= widget->width - 10; for (i=entry->display_pos; ilength && width > 0; i++) { width -= glutBitmapWidth (widget->font, entry->text[i]); } entry->display_pos = i; } finfo = glut_get_bitmap_font_info (widget->font); x = widget->x0 + 2; y = widget->y0 + finfo->descent + (widget->height - finfo->height) / 2; if (state == GR_STATE_FOCUS) { if (entry->calet_pos >= entry->display_pos) { calet_width = glut_bitmap_string_width (widget->font, entry->text + entry->display_pos, entry->calet_pos - entry->display_pos); if (entry->calet_pos < entry->length) { width = glutBitmapWidth (widget->font, entry->text[entry->calet_pos]); } else { width = glutBitmapWidth (widget->font, ' '); } GL_CHECK(glColor3f (1, 0, 0)); GL_CHECK(glRecti (x + calet_width - 1, widget->y0 + 1, x + calet_width + width, widget->y1 - 1)); } width = 4; GL_CHECK(glColor4fv (widget->fg_color[state])); GL_CHECK(glRasterPos3i (x, y, 1)); for (i=entry->display_pos; ilength; i++) { width += glutBitmapWidth (widget->font, entry->text[i]); if (width > widget->width) break; } glut_bitmap_string (widget->font, entry->text + entry->display_pos, i - entry->display_pos); } else { glColor4fv (widget->fg_color[state]); glRasterPos3i (x, y, 1); width = 10; for (i=entry->display_pos; ilength; i++) { width += glutBitmapWidth (widget->font, entry->text[i]); if (width > widget->width) break; } glut_bitmap_string (widget->font, entry->text + entry->display_pos, i - entry->display_pos); } } #define CTRL(key) (key - 'a' + 1) static void default_entry_keyboard (GlutObject obj, unsigned char key, int x, int y) { GlutEntry *entry = obj; int modifiers; modifiers = glutGetModifiers (); switch (key) { case '\r': glut_entry_invoke (obj); break; case '\t': if (modifiers) { focus_widget = glut_previous_focus_widget (focus_widget); } else { focus_widget = glut_next_focus_widget (focus_widget); } glut_post_redisplay (); break; case CTRL('a'): entry->calet_pos = 0; glut_post_redisplay (); break; case CTRL('b'): if (entry->calet_pos > 0) { entry->calet_pos --; glut_post_redisplay (); } break; case CTRL('d'): if (entry->calet_pos < entry->length) { memmove (entry->text + entry->calet_pos, entry->text + entry->calet_pos + 1, entry->length - entry->calet_pos - 1); entry->length --; if (entry->changed_func) { (*entry->changed_func) (entry); } glut_post_redisplay (); } break; case CTRL('e'): entry->calet_pos = entry->length; glut_post_redisplay (); break; case CTRL('f'): if (entry->calet_pos < entry->length) { entry->calet_pos ++; glut_post_redisplay (); } break; case CTRL('h'): if (entry->calet_pos > 0) { memmove (entry->text + entry->calet_pos - 1, entry->text + entry->calet_pos, entry->length - entry->calet_pos); entry->length --; entry->calet_pos --; if (entry->changed_func) { (*entry->changed_func) (entry); } glut_post_redisplay (); } break; case CTRL('k'): entry->length = entry->calet_pos; if (entry->changed_func) { (*entry->changed_func) (entry); } glut_post_redisplay (); break; default: if (isprint (key)) { memmove (entry->text + entry->calet_pos + 1, entry->text + entry->calet_pos, entry->length - entry->calet_pos); entry->text[entry->calet_pos] = key; entry->length ++; entry->calet_pos ++; if (entry->changed_func) { (*entry->changed_func) (entry); } glut_post_redisplay (); } } } static void default_entry_mouse (GlutObject obj, int button, int state, int x, int y) { GlutWidget *widget = obj; GlutEntry *entry = obj; int pos; int width = 0; int i; if (state == GLUT_DOWN) { focus_widget = obj; pos = x - widget->x0 - 2; for (i=entry->display_pos; ilength; i++) { width += glutBitmapWidth (widget->font, entry->text[i]); if (pos < width) break; } entry->calet_pos = i; glut_post_redisplay (); } } static void glut_bitmap_string (void *font, char *string, int length) { int i, c; GlutFontInfo *finfo = glut_get_bitmap_font_info (font); if (!finfo) return; for (i=0; icompiled[c]) { glCallList (finfo->dl + c); } else { glNewList (finfo->dl + c, GL_COMPILE_AND_EXECUTE); glutBitmapCharacter (finfo->font, c); glEndList (); finfo->compiled[c] = 1; } } } static void default_label_display (GlutObject obj) { GlutWidget *widget = obj; GlutLabel *label = obj; GlutFontInfo *finfo; int i, j, line; int width = 0; int x = 0, y; if (label->justify == -1) label->justify = widget->anchor & GR_HORIZONTAL_MASK; if (label->length > 0) { switch (label->justify) { case GR_LEFT: x = widget->x0; break; case GR_RIGHT: width = glut_label_width (obj) / 2; break; } glColor4fv (widget->fg_color[GR_STATE_NORMAL]); finfo = glut_get_bitmap_font_info (widget->font); j=0; glRasterPos3i (widget->x0, widget->y0 + finfo->descent, 1); line = 0; for (i=0; ilength; i++) { for (j=i; jlength && label->title[j] != '\n'; j++) {} y = widget->y0 + finfo->descent - (finfo->height + finfo->descent) * line; if (y < screen_height / 2 && y > -screen_height / 2) { switch (label->justify) { case GR_CENTER: width = glut_bitmap_string_width (widget->font, label->title + i, j-i); x = widget->x0 + (widget->width - width) / 2; break; case GR_RIGHT: x = widget->x1 - glut_bitmap_string_width (widget->font, label->title + i, j-i); break; } glRasterPos3i (x, widget->y0 + finfo->descent - (finfo->height + finfo->descent) * line, 1); glut_bitmap_string (widget->font, label->title + i, j - i); } i = j; line ++; } } }