/** * @brief Toolkit input handled here. * * @param event Event to handle. * @return 1 if input was used, 0 if it wasn't. */ int toolkit_input( SDL_Event* event ) { int ret; Window *wdw, *wlast; Widget *wgt; /* Get window that can be focused. */ wlast = NULL; for (wdw = windows; wdw!=NULL; wdw = wdw->next) { if (!window_isFlag( wdw, WINDOW_NOINPUT ) && !window_isFlag( wdw, WINDOW_KILL )) wlast = wdw; } if (wlast == NULL) return 0; wdw = wlast; /* See if widget needs event. */ for (wgt=wdw->widgets; wgt!=NULL; wgt=wgt->next) { if (wgt_isFlag( wgt, WGT_FLAG_RAWINPUT )) { if (wgt->rawevent != NULL) { ret = wgt->rawevent( wgt, event ); if (ret != 0) return ret; } } } /* Pass event to window. */ return toolkit_inputWindow( wdw, event, 1 ); }
/** * @brief Checks to see if a widget is focusable. * * @param wgt Widget to check if is focusable. * @return 1 if it's focusable, 0 if it isn't. */ static int toolkit_isFocusable( Widget *wgt ) { if (wgt==NULL) return 0; return wgt_isFlag(wgt, WGT_FLAG_CANFOCUS); }
/** * @brief Allocates room for a new widget. * * @param w Window to create widget in. * @return Newly allocated widget. */ Widget* window_newWidget( Window* w, const char *name ) { Widget *wgt, *wlast, *wtmp; /* NULL protection. */ if (w==NULL) return NULL; /* Try to find one with the same name first. */ wlast = NULL; for (wgt=w->widgets; wgt!=NULL; wgt=wgt->next) { /* Must match name. */ if (strcmp(name, wgt->name)!=0) { wlast = wgt; continue; } /* Should be destroyed. */ if (!wgt_isFlag( wgt, WGT_FLAG_KILL )) { WARN("Trying to create widget '%s' over existing one that hasn't been destroyed", name ); return NULL; } /* Relink. */ if (wlast==NULL) w->widgets = wgt->next; else wlast->next = wgt->next; /* Prepare and return this widget. */ widget_cleanup(wgt); break; } /* Must grow widgets. */ if (wgt == NULL) wgt = malloc( sizeof(Widget) ); /* Sane defaults. */ memset( wgt, 0, sizeof(Widget) ); wgt->type = WIDGET_NULL; wgt->status = WIDGET_STATUS_NORMAL; wgt->wdw = w->id; wgt->name = strdup(name); wgt->id = ++w->idgen; /* Set up. */ wlast = NULL; for (wtmp=w->widgets; wtmp!=NULL; wtmp=wtmp->next) wlast = wtmp; if (wlast == NULL) w->widgets = wgt; else wlast->next = wgt; return wgt; }
/** * @brief Checks to see if a widget exists. * * @param wid Window to check widget in. * @param wgtname Name of the widget to check; * @return 1 if the widget exists. */ int widget_exists( const unsigned int wid, const char* wgtname ) { Window *w = window_wget(wid); Widget *wgt; /* Get window. */ if (w==NULL) { WARN("window '%d' does not exist", wid); return 0; } /* Check for widget. */ for (wgt=w->widgets; wgt!=NULL; wgt=wgt->next) if (strcmp(wgtname, wgt->name)==0) return !wgt_isFlag(wgt, WGT_FLAG_KILL); return 0; }
/** * @brief Renders a input widget. * * @param inp Input widget to render. * @param bx Base X position. * @param by Base Y position. */ static void inp_render( Widget* inp, double bx, double by ) { double x, y, ty; char buf[ PATH_MAX ]; int w; int m; x = bx + inp->x; y = by + inp->y; /* main background */ toolkit_drawRect( x, y, inp->w, inp->h, &cWhite, NULL ); /* center vertically */ if (inp->dat.inp.oneline) ty = y - (inp->h - gl_smallFont.h)/2.; else { WARN("Multi-line input widgets unsupported atm."); return; } /* Draw text. */ gl_printTextRaw( inp->dat.inp.font, inp->w-10., inp->h, x+5., ty, &cBlack, &inp->dat.inp.input[ inp->dat.inp.view ] ); /* Draw cursor. */ if (wgt_isFlag( inp, WGT_FLAG_FOCUSED )) { m = MIN( inp->dat.inp.pos - inp->dat.inp.view, PATH_MAX-1 ); strncpy( buf, &inp->dat.inp.input[ inp->dat.inp.view ], m ); buf[ m ] = '\0'; w = gl_printWidthRaw( inp->dat.inp.font, buf ); toolkit_drawRect( x+5.+w, y + (inp->h - inp->dat.inp.font->h - 4.)/2., 1., inp->dat.inp.font->h + 4., &cBlack, &cBlack ); } /* inner outline */ toolkit_drawOutline( x, y, inp->w, inp->h, 0., toolkit_colLight, toolkit_col ); /* outter outline */ toolkit_drawOutline( x, y, inp->w, inp->h, 1., toolkit_colDark, NULL ); }
/** * @brief Updates the toolkit input for repeating keys. */ void toolkit_update (void) { unsigned int t; Window *wdw; Widget *wgt; char buf[2]; SDL_Event event; int ret; /* Clean up the dead if needed. */ if (!dialogue_isOpen()) { /* Hack, since dialogues use secondary loop. */ if (toolkit_delayCounter > 0) toolkit_delayCounter--; else toolkit_purgeDead(); } /* Killed all the windows. */ if (windows == NULL) { SDL_ShowCursor(SDL_DISABLE); toolkit_open = 0; /* disable toolkit */ if (paused) unpause_game(); } /* Must have a key pressed. */ if (input_key == 0) return; t = SDL_GetTicks(); /* Should be repeating. */ if (input_keyTime + INPUT_DELAY + input_keyCounter*INPUT_FREQ > t) return; /* Increment counter. */ input_keyCounter++; /* Check to see what it affects. */ if (windows != NULL) { /* Get the window. */ wdw = toolkit_getActiveWindow(); if (wdw == NULL) return; /* See if widget needs event. */ for (wgt=wdw->widgets; wgt!=NULL; wgt=wgt->next) { if (wgt_isFlag( wgt, WGT_FLAG_RAWINPUT )) { if (wgt->rawevent != NULL) { event.type = SDL_KEYDOWN; event.key.state = SDL_PRESSED; event.key.keysym.sym = input_key; event.key.keysym.mod = 0; ret = wgt->rawevent( wgt, &event ); if (ret != 0) return; } } } /* Handle the focused widget. */ wgt = toolkit_getFocus( wdw ); if ((wgt != NULL) && (wgt->keyevent != NULL)) { wgt->keyevent( wgt, input_key, 0 ); } if ((input_text != 0) && (wgt != NULL) && (wgt->textevent != NULL)) { buf[0] = input_text; buf[1] = '\0'; wgt->textevent( wgt, buf ); } } }
/** * @brief Purges the dead windows. */ static void toolkit_purgeDead (void) { Window *wdw, *wlast, *wkill; Widget *wgt, *wgtlast, *wgtkill; /* Only clean up if necessary. */ if (!window_dead) return; /* Must be windows. */ if (windows == NULL) return; /* Destroy what is needed. */ wlast = NULL; wdw = windows; while (wdw != NULL) { if (window_isFlag( wdw, WINDOW_KILL )) { /* Save target. */ wkill = wdw; /* Reattach linked list. */ if (wlast == NULL) windows = wdw->next; else wlast->next = wdw->next; wdw = wlast; /* Kill target. */ wkill->next = NULL; window_kill( wkill ); } else { wgtlast = NULL; wgt = wdw->widgets; while (wgt != NULL) { if (wgt_isFlag( wgt, WGT_FLAG_KILL )) { /* Save target. */ wgtkill = wgt; /* Reattach linked list. */ if (wgtlast == NULL) wdw->widgets = wgt->next; else wgtlast->next = wgt->next; wgt = wgtlast; /* Kill target. */ wgtkill->next = NULL; widget_kill( wgtkill ); } /* Save position. */ wgtlast = wgt; if (wgt == NULL) wgt = wdw->widgets; else wgt = wgt->next; } } /* Save position. */ wlast = wdw; if (wdw == NULL) wdw = windows; else wdw = wdw->next; } /* Nothing left to purge. */ window_dead = 0; }
/** * @brief Handle widget mouse input. * * @param w Window to which widget belongs. * @param wgt Widget recieving event. * @param event Event recieved by the window. */ static void toolkit_mouseEventWidget( Window *w, Widget *wgt, Uint8 type, Uint8 button, int x, int y, int rx, int ry ) { int inbounds; /* Widget translations. */ x -= wgt->x; y -= wgt->y; /* Check inbounds. */ inbounds = !((x < 0) || (x >= wgt->w) || (y < 0) || (y >= wgt->h)); /* Regular widgets. */ switch (type) { case SDL_MOUSEMOTION: /* Change the status of the widget if mouse isn't down. */ /* Not scrolling. */ if (wgt->status != WIDGET_STATUS_SCROLLING) { if (inbounds) { if (wgt->status != WIDGET_STATUS_MOUSEDOWN) wgt->status = WIDGET_STATUS_MOUSEOVER; } else wgt->status = WIDGET_STATUS_NORMAL; } else inbounds = 1; /* Scrolling is always inbounds. */ /* If always gets the event. */ if (wgt_isFlag( wgt, WGT_FLAG_ALWAYSMMOVE )) inbounds = 1; /* Try to give the event to the widget. */ if (inbounds && (wgt->mmoveevent != NULL)) (*wgt->mmoveevent)( wgt, x, y, rx, ry ); break; case SDL_MOUSEBUTTONDOWN: if (!inbounds) break; /* Update the status. */ if (button == SDL_BUTTON_LEFT) wgt->status = WIDGET_STATUS_MOUSEDOWN; if (toolkit_isFocusable(wgt)) w->focus = wgt->id; /* Try to give the event to the widget. */ if (wgt->mclickevent != NULL) (*wgt->mclickevent)( wgt, button, x, y ); break; case SDL_MOUSEBUTTONUP: /* Since basically only buttons are handled here, we ignore * it all except the left mouse button. */ if (button != SDL_BUTTON_LEFT) break; if (wgt->status==WIDGET_STATUS_MOUSEDOWN) { if ((wgt->type==WIDGET_BUTTON) && (wgt->dat.btn.disabled==0)) { if (wgt->dat.btn.fptr==NULL) DEBUG("Toolkit: Button '%s' of Window '%s' " "doesn't have a function trigger", wgt->name, w->name ); else { (*wgt->dat.btn.fptr)(w->id, wgt->name); } } } /* Always goes normal unless is below mouse. */ if (inbounds) wgt->status = WIDGET_STATUS_MOUSEOVER; else wgt->status = WIDGET_STATUS_NORMAL; break; } }