📄 widgets.c
字号:
y = ev->button.y; where = whereInSlider(sp, x, y); if (sp->type == VSliderType) { pos = y - sp->y; len = sp->h; } else if (sp->type == HSliderType) { pos = x - sp->x; len = sp->w; } else return; len -= (size + 2 * SLIDERBUTTONSIZE); if (ev->type == SDL_MOUSEMOTION) { if (sp->drag) { pos -= (SLIDERBUTTONSIZE + SLIDERBUTTONSIZE / 2); if (pos < 0) pos = 0; if (pos > len) pos = len; sp->position = pos; pc = (pos * 100) / len; sp->pc = pc; sp->offset = (sp->range * pc) / 100; } } else if (ev->type == SDL_MOUSEBUTTONDOWN) { sp->state = where; switch (where) { case MOUSE_IN_UPPER_SLIDER: adjustSlider(slider, -sp->change); if (tweakSlider(sp, x, y, MOUSE_IN_UPPER_SLIDER)) { sp->state = MOUSE_NOT_IN_SLIDER; timerData.vs = NULL; sp->drag = TRUE; } else { widgetRepeatDelay = WIDGET_SLIDER_REPEAT_DELAY; timerData.vs = sp; } break; case MOUSE_IN_LOWER_SLIDER: adjustSlider(slider, sp->change); if (tweakSlider(sp, x, y, MOUSE_IN_LOWER_SLIDER)) { sp->state = MOUSE_NOT_IN_SLIDER; timerData.vs = NULL; sp->drag = TRUE; } else { widgetRepeatDelay = WIDGET_SLIDER_REPEAT_DELAY; timerData.vs = sp; } break; case MOUSE_ON_SLIDER: sp->drag = TRUE; break; case MOUSE_IN_SLIDER_UPBUTTON: adjustSlider(slider, -1); widgetRepeatDelay = WIDGET_SLIDER_REPEAT_DELAY; timerData.vs = sp; break; case MOUSE_IN_SLIDER_DOWNBUTTON: adjustSlider(slider, 1); widgetRepeatDelay = WIDGET_SLIDER_REPEAT_DELAY; timerData.vs = sp; break; } } else if (ev->type == SDL_MOUSEBUTTONUP) { sp->drag = FALSE; }}// Pop a Widget to the top of the widget listvoid popUpWidget(void *x){ if (!x || x == topWidget) return; removeWList(x); addWList(x); topWidget = x; if (((WIDGET *) x)->p.type == InputBoxType) timerData.vs = x;}// Remove a Widget from the widget list and update screenvoid pushDownWidget(void *x){ if (!x) return; removeWList(x); updateScreen();}// Add a Widget to the widget listvoid addWList(void *w){ WLIST *next, *prev; if (!wlist) { wlist = (WLIST *) malloc(sizeof(WLIST)); next = wlist; } else { prev = NULL; next = prev = wlist; while (next) { if (next->w == w) // already in list return; prev = next; next = next->next; } prev->next = (WLIST *) malloc(sizeof(WLIST)); next = prev->next; } next->w = w; next->next = NULL;}// Remove a Widget from the widget listvoid removeWList(void *w){ WLIST *prev, *next; WIDGET *x, *y; BLIST *list; if (!wlist) return; prev = NULL; next = wlist; while (next && next->w != w) // find widget in list { prev = next; next = next->next; } if (next) // widget found in list { // remove widget from list if (prev) // if not first on list... prev->next = next->next; // unlink from list else // else was first on list wlist = next->next; // so new head is our next x = (WIDGET *) w; switch (x->p.type) // check for children of this widget { case WindowType: case MenuType: case VMenuType: case AlertType: case NoticeType: case TextBoxType: case InputBoxType: list = ((WINDOW *) x)->list; while (list) // remove any children found { y = (WIDGET *) list->thislist.button; removeWList(y); list = list->next; } break; } free(next); } next = wlist; if (next) { while (next->next) next = next->next; topWidget = next->w; if (((WIDGET *) topWidget)->p.type == InputBoxType) timerData.vs = topWidget; } else { topWidget = NULL; timerData.vs = NULL; }}// Scan the active widget list and re-display the widgetsvoid updateScreen(void){ WLIST *next; blankScreen(); next = wlist; while (next) { showWidget(next->w); next = next->next; } SDL_UpdateRect(screen, 0, 0, 0, 0);}// Update input box stringvoid updateIBox(SDL_Event *event, INPUTBOX *b){ int i, len, row, column; char *str; Uint16 chr; SLIST *sl, *slprev; if (b != topWidget) popUpWidget(b); if (event->type == SDL_KEYDOWN) { chr = event->key.keysym.unicode; sl = b->text; i = b->line + b->cursory; while (i && sl) { sl = sl->next; --i; } if (sl) { str = sl->str; if (str) { len = strlen(str); if (isprint(chr) && (len < b->w / FONT_WIDTH - 1 || b->mode == IBOX_OVERWRITE_MODE)) { if (b->mode == IBOX_INSERT_MODE) shiftStringUp(str, b->cursorx); str[b->cursorx] = chr; i = b->w / FONT_WIDTH - 1; len = b->cursorx + 1; if (len >= i) len = i - 1; b->cursorx = len; } else if (chr == '\n' || chr == '\r') { b->cursorx = 0; if (b->cursory < b->vlines - 1) b->cursory++; else if (b->line < b->lines - b->vlines) b->line++; } else if (chr == '\b' && b->cursorx) { b->cursorx--; shiftStringDown(str, b->cursorx); } else { switch (event->key.keysym.sym) { case SDLK_DELETE: shiftStringDown(str, b->cursorx); break; case SDLK_BACKSPACE: if (b->cursorx) { shiftStringDown(str, b->cursorx-1); b->cursorx -= 1; } break; case SDLK_INSERT: b->mode ^= 1; break; case SDLK_HOME: b->cursorx = 0; break; case SDLK_END: i = b->w / FONT_WIDTH - 1; if (len >= i) len = i - 1; b->cursorx = len; break; case SDLK_UP: if (b->cursory) b->cursory--; else if (b->line) b->line--; sl = b->text; i = b->cursory + b->line; if (i >= b->lines) i = b->lines - 1; while (i) { sl = sl->next; --i; } str = sl->str; if (str && strlen(str) < b->cursorx) b->cursorx = strlen(str); break; case SDLK_DOWN: if (b->cursory < b->vlines - 1) b->cursory++; else if (b->line < b->lines - b->vlines) b->line++; sl = b->text; i = b->cursory + b->line; if (i >= b->lines) i = b->lines - 1; while (i) { sl = sl->next; --i; } str = sl->str; len = strlen(str); if (str && len < b->cursorx) b->cursorx = len; break; case SDLK_LEFT: if (b->cursorx) b->cursorx--; break; case SDLK_RIGHT: b->cursorx++; sl = b->text; i = b->cursory + b->line; while (i) { sl = sl->next; --i; } str = sl->str; len = strlen(str) - 1; if (len < 0) len = 0; if (str && len < b->cursorx) b->cursorx = len; break; default: break; } } } } } else if (event->type == SDL_MOUSEBUTTONDOWN) { if (event->button.button == SDL_BUTTON_RIGHT) { b->mode ^= 1; } else if (event->button.button == SDL_BUTTON_LEFT) // Thanks to Pat Cevasco for this mod { sl = b->text;// The location of the mouse click (in line and character units) row = (event->button.y - b->y - 4) / FONT_HEIGHT; column = (event->button.x - b->x - 4) / FONT_WIDTH; if (column < 0) column = 0; i = b->line + row; while (i) // Find the string of the line that was clicked on { slprev = sl; sl = sl->next; if (!sl) { sl = slprev; --row; break; } --i; } str = sl->str; len = strlen(str) - 1; // Check the length of the line of interest if (len < 0) len = 0; if (row > b->vlines - 1) row = b->vlines - 1; else if (row < 0) row = 0;// Account for clicking on a location after last character of text in the line.// Use len + 1 so that the cursor will be placed after the last character. if (len < 1) column = 0; else if (len + 1 < column) column = len + 1; b->cursorx = column; // move cursor b->cursory = row; } }}// Check widget list for callback to processvoid processCB(SDL_Event *ev){ int x, y; int xlo, xhi, ylo, yhi; WLIST *next; MENU *m; MENU *last; VSLIDER *vs; void (*fptr)(SDL_Event *, void *); WIDGET *widget; int type; int evtype; ALERT *alert; BLIST *blist; BUTTON *btn; void *parent; x = ev->button.x; y = ev->button.y; fptr = NULL; widget = (WIDGET *) topWidget; evtype = ev->type; if (evtype == TIMER_EVENT) { widgetTimerCB(); return; } if (widget) { type = widget->p.type;// If any alert or notice is active (topWidget), process only mouse button// down events on the callbacks for its Cancel and Ok buttons. if ((type == AlertType) || (type == NoticeType)) { alert = (ALERT *) widget; if (evtype == SDL_MOUSEBUTTONDOWN) { blist = alert->list; blist = blist->next; btn = blist->thislist.button; // check if cancel/close button xlo = btn->x; xhi = xlo + btn->w; ylo = btn->y; yhi = ylo + btn->h; if (x >= xlo && x <= xhi && y >= ylo && y <= yhi) { fptr = btn->mdfunc; (*fptr)(ev, btn); updateScreen(); return; } if (type == AlertType) { blist = blist->next; btn = blist->thislist.button; // check if ok button xlo = btn->x; xhi = xlo + btn->w; ylo = btn->y; yhi = ylo + btn->h; if (x >= xlo && x <= xhi && y >= ylo && y <= yhi) { fptr = btn->mdfunc; (*fptr)(ev, btn); updateScreen(); } } } else if (evtype == SDL_KEYDOWN) { if (ev->key.keysym.unicode == SDLK_RETURN) { blist = alert->list; blist = blist->next; btn = blist->thislist.button; // get button callback fptr = btn->mdfunc; (*fptr)(ev, btn); updateScreen(); } } return; } }// No alert or notice is active, scan the list of active widgets// and process the LAST (topmost) widget for which the callback// parameters match. next = wlist; last = NULL; switch (evtype) { case SDL_MOUSEBUTTONDOWN: while (next) { m = (MENU *) next->w; if (m->type == VSliderType || m->type == HSliderType) { vs = (VSLIDER *) m; vs->drag = FALSE; vs->state = MOUSE_NOT_IN_SLIDER; } if (m && m->mdfunc) { xlo = m->x; xhi = xlo + m->w; ylo = m->y; yhi = ylo + m->h; if (x >= xlo && x <= xhi && y >= ylo && y <= yhi) { fptr = m->mdfunc; last = m; } } next = next->next; } break; case SDL_MOUSEBUTTONUP: if (widget && (widget->p.type == VSliderType || widget->p.type == HSliderType)) timerData.vs = NULL; while (next) { m = (MENU *) next->w; if (m->type == VSliderType || m->type == HSliderType) { vs = (VSLIDER *) m; vs->drag = FALSE; vs->state = MOUSE_NOT_IN_SLIDER; } if (m && m->mufunc) { xlo = m->x; xhi = xlo + m->w; ylo = m->y; yhi = ylo + m->h; if (x >= xlo && x <= xhi && y >= ylo && y <= yhi) { fptr = m->mufunc; last = m; } } next = next->next; } break; case SDL_MOUSEMOTION: while (next) { m = (MENU *) next->w; if (m && m->mmfunc) { fptr = m->mmfunc; last = m; if (m == topWidget) break; } next = next->next; } break; case SDL_KEYDOWN: while (next) { m = (MENU *) next->w; if (m && m->kdfunc) { fptr = m->kdfunc; last = m; if (m == topWidget) break; } next = next->next; } break; case SDL_KEYUP: while (next) { m = (MENU *) next->w; if (m && m->kufunc) { fptr = m->kufunc; last = m; if (m == topWidget) break; } next = next->next; } break; } if (fptr) // fptr points to the last callback that matches, if any { if (last->type == VSliderType || last->type == HSliderType) { if (evtype != SDL_MOUSEMOTION || ((VSLIDER *) last)->drag) { if (last != topWidget)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -