📄 widgets.c
字号:
/* * widgets.c - SDL widget set in C * * Copyright 2004 by Jeffery L. Post * theposts<AT>pacbell<DOT>net * Version 0.0.3 - 11/26/04 * * 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 <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <signal.h>#include <sys/time.h>#include "widgets.h"#define CURSOR_Y_OFFSET 1 // this insures that the cursor is under the character// We use a system interval timer because SDL timers screw up popen(), exec(), etc.#define WIDGET_TIMER_UPDATE_TIME 50#define WIDGET_SLIDER_REPEAT_DELAY 3#define IBOX_CURSOR_DELAY 5struct timer_data { int *timeout; VSLIDER *vs;};extern SDL_Surface *screen;// Local prototypesvoid widgetTimerCB(void);void blankScreen(void);int printString(int x, int y, int fg, int bg, char *str);int printHLString(int x, int y, int fg, int bg, char *str);void drawCursor(int x, int y, int fg, char chr);void setPixel(int x, int y, int color);void shiftStringUp(char *str, int index);void shiftStringDown(char *str, int index);int whereInSlider(void *slider, int mx, int my);bool tweakSlider(VSLIDER *sp, int x, int y, int where);void adjustSlider(void *slider, int amount);void updateSlider(SDL_Event *ev, void *slider);void makeBar(int x, int y, int w, int h, int color);void processAlertCallBack(SDL_Event *ev, BUTTON * btn);void processNoticeCallBack(SDL_Event *ev, BUTTON * btn);bool childInParent(void *parent, void *child);int maxWidth(WINDOW *win);void updateIBox(SDL_Event *event, INPUTBOX *b);void showWindow(WINDOW *w);void showVMenu(VMENU *w);void showAlertBox(WINDOW *w);void showNoticeBox(WINDOW *w);void showTextBox(TEXTBOX *w);void showInputBox(INPUTBOX *w);void showButton(BUTTON *b);void showLabel(LABEL *lab);void showHLabel(HLABEL *lab);void showCheckBox(CHECKBOX *cb);void showLeftArrow(int x, int y);void showRightArrow(int x, int y);void showUpArrow(int x, int y);void showDownArrow(int x, int y);void showVSlider(VSLIDER *vs);void showHSlider(HSLIDER *hs);void addWList(void *w);void removeWList(void *w);// Global variables#ifdef DEBUG// widget_names MUST match enum WidgetType in widgets.hchar *widget_names[] = { "Window", "Menu", "VMenu", "Button", "CheckBox", "Label", "HLabel", "Alert", "Notice", "TextBox", "InputBox", "VSlider", "HSlider", "Invalid Widget",};#endif // DEBUGint widgetRepeatDelay = WIDGET_SLIDER_REPEAT_DELAY;#ifndef WIN32struct itimerval vtimer;#endifstruct timer_data timerData = { &widgetRepeatDelay, NULL,};// Simulated mouse button down event for automatic callbacksSDL_MouseButtonEvent timerEvent = { SDL_MOUSEBUTTONDOWN, // simulate mouse button down event 0, // mouse device index 0, // mouse button index SDL_PRESSED, // state 0, // x coordinate 0, // y coordinate};// Timer event for auto callbackSDL_Event AlarmEvent = {TIMER_EVENT};int widget_id = 0;void *topWidget = NULL;int screen_width;int screen_height;Uint8 bits_per_pixel;Uint8 bytes_per_pixel;Uint16 pitch;// ColorsUint32 black; // 0Uint32 blue; // 1Uint32 green; // 2Uint32 cyan; // 3Uint32 red; // 4Uint32 magenta; // 5Uint32 brown; // 6Uint32 lgray; // 7Uint32 gray; // 8Uint32 lblue; // 9Uint32 lgreen; // 10Uint32 lcyan; // 11Uint32 lred; // 12Uint32 lmagenta; // 13Uint32 yellow; // 14Uint32 white; // 15Uint32 lyellow; // 16Uint32 dyellow; // 17Uint32 pink; // 18Uint32 dblue; // 19Uint32 dgreen; // 20WLIST *wlist = NULL;#ifdef DEBUGvoid dump_widget_list(void){ int i; WLIST *next; WIDGET *w; printf("\nWidget List at 0x%x:\n", (int) wlist); next = wlist; i = 1; while (next) { w = next->w; printf("%2d: widget %d at 0x%x, entry 0x%x, %s, parent 0x%x, x %d, y %d, w %d, h %d.", i, w->p.id, (int) w, (int) next, widget_names[w->p.type], (int) w->p.parent, w->p.x, w->p.y, w->p.w, w->p.h); printf(" Callbacks: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", (int) w->p.mdfunc, (int) w->p.mufunc, (int) w->p.mmfunc, (int) w->p.kdfunc, (int) w->p.kufunc); fflush(stdout); next = next->next; i++; } if (topWidget) printf("topWidget 0x%x, %s\n", (int) topWidget, widget_names[((WIDGET *) topWidget)->p.type]);}#endif/* * Functions * */void SigHandler(int sig){#ifndef WIN32 if (sig == SIGALRM) SDL_PushEvent(&AlarmEvent);#else SDL_PushEvent(&AlarmEvent);#endif}// Display a character with given colors at given coordinatesvoid drawChar(int x, int y, int fg, int bg, char chr){ int i, j, b; int bpp, neg; Uint8 *row; b = (int) (Uint8) chr * FONT_WIDTH * FONT_HEIGHT; bpp = (int) bytes_per_pixel; neg = FONT_WIDTH * bpp; row = (Uint8 *) screen->pixels + y * pitch + x * bpp; switch (bytes_per_pixel) { case 1: for (i=0; i<FONT_HEIGHT; i++, y++) { row += pitch; for (j=0; j<FONT_WIDTH; j++) { if (fontdata[b + j]) *row = (Uint8) fg; else *row = (Uint8) bg; row += bpp; } b += FONT_WIDTH; row -= neg; } break; case 2: for (i=0; i<FONT_HEIGHT; i++, y++) { row += pitch; for (j=0; j<FONT_WIDTH; j++) { if (fontdata[b + j]) *(Uint16 *)row = (Uint16) fg; else *(Uint16 *)row = (Uint16) bg; row += bpp; } b += FONT_WIDTH; row -= neg; } break; case 4: for (i=0; i<FONT_HEIGHT; i++, y++) { row += pitch; for (j=0; j<FONT_WIDTH; j++) { if (fontdata[b + j]) *(Uint32 *)row = (Uint32) fg; else *(Uint32 *)row = (Uint32) bg; row += bpp; } b += FONT_WIDTH; row -= neg; } break; }}// Display cursorvoid drawCursor(int x, int y, int fg, char chr){ int i, j, b; int bpp, neg; Uint8 *row; b = (int) (Uint8) chr * FONT_WIDTH * FONT_HEIGHT; bpp = (int) bytes_per_pixel; neg = FONT_WIDTH * bpp; y += CURSOR_Y_OFFSET; row = (Uint8 *) screen->pixels + y * pitch + x * bpp; switch (bytes_per_pixel) { case 1: for (i=0; i<FONT_HEIGHT; i++, y++) { row += pitch; for (j=0; j<FONT_WIDTH; j++) { if (fontdata[b + j]) *row = (Uint8) fg; row += bpp; } b += FONT_WIDTH; row -= neg; } break; case 2: for (i=0; i<FONT_HEIGHT; i++, y++) { row += pitch; for (j=0; j<FONT_WIDTH; j++) { if (fontdata[b + j]) *(Uint16 *)row = (Uint16) fg; row += bpp; } b += FONT_WIDTH; row -= neg; } break; case 4: for (i=0; i<FONT_HEIGHT; i++, y++) { row += pitch; for (j=0; j<FONT_WIDTH; j++) { if (fontdata[b + j]) *(Uint32 *)row = (Uint32) fg; row += bpp; } b += FONT_WIDTH; row -= neg; } break; }}// Set pixel at given coordinates to the given colorvoid setPixel(int x, int y, int color){ Uint8 *row8; Uint16 *row16; Uint32 *row32; switch (bytes_per_pixel) { case 1: row8 = (Uint8 *) ((int) screen->pixels + y * pitch + x * bytes_per_pixel); *row8 = (Uint8) color; break; case 2: row16 = (Uint16 *) ((int) screen->pixels + y * pitch + x * bytes_per_pixel); *row16 = (Uint16) color; break; case 4: row32 = (Uint32 *) ((int) screen->pixels + y * pitch + x * bytes_per_pixel); *row32 = (Uint32) color; break; }}// Display a stringint printString(int x, int y, int fg, int bg, char *str){ int i; char chr; i = 0; while (*str) { chr = *str++; drawChar(x, y, fg, bg, chr); x += FONT_WIDTH; i++; } return i;}// Display a highlighted stringint printHLString(int x, int y, int fg, int bg, char *str){ int i; char chr; i = 0; while (*str) { chr = *str++; if (chr & 0x80) drawChar(x, y, bg, fg, chr & 0x7f); else drawChar(x, y, fg, bg, chr); x += FONT_WIDTH; i++; } return i;}void shiftStringUp(char *str, int index){ int len; len = strlen(str); while (len > index) { str[len] = str[len - 1]; --len; }}void shiftStringDown(char *str, int index){ do { str[index] = str[index + 1]; index++; } while (str[index]);}// Initialize the video systemvoid initWidgets(void){ SDL_VideoInfo *v_info; SDL_PixelFormat *vfmt; v_info = (SDL_VideoInfo *) SDL_GetVideoInfo(); if (!v_info) { printf("\n\nCan't get video info: %s\n\n", SDL_GetError()); exit(1); } screen_width = screen->w; screen_height = screen->h; vfmt = screen->format; bits_per_pixel = vfmt->BitsPerPixel; bytes_per_pixel = vfmt->BytesPerPixel; pitch = screen->pitch; SDL_EnableUNICODE(TRUE);#ifndef WIN32 signal(SIGALRM, SigHandler); // set up a signal handler vtimer.it_interval.tv_sec = 0; // set a 50msec interval timer vtimer.it_interval.tv_usec = (WIDGET_TIMER_UPDATE_TIME * 1000); vtimer.it_value.tv_sec = 0; vtimer.it_value.tv_usec = (WIDGET_TIMER_UPDATE_TIME * 1000); setitimer(ITIMER_REAL, &vtimer, NULL);#else SetTimer(NULL, 0, WIDGET_TIMER_UPDATE_TIME, (VOID CALLBACK*) &SigHandler);#endif// R G B black = SDL_MapRGB(vfmt, (Uint8) 0x00, (Uint8) 0x00, (Uint8) 0x00); // 0 blue = SDL_MapRGB(vfmt, (Uint8) 0x00, (Uint8) 0x00, (Uint8) 0xd0); // 1 green = SDL_MapRGB(vfmt, (Uint8) 0x00, (Uint8) 0xd0, (Uint8) 0x00); // 2 cyan = SDL_MapRGB(vfmt, (Uint8) 0x00, (Uint8) 0xa6, (Uint8) 0xa6); // 3 red = SDL_MapRGB(vfmt, (Uint8) 0xa6, (Uint8) 0x00, (Uint8) 0x00); // 4 magenta = SDL_MapRGB(vfmt, (Uint8) 0xa6, (Uint8) 0x00, (Uint8) 0xa6); // 5 brown = SDL_MapRGB(vfmt, (Uint8) 0xa6, (Uint8) 0x54, (Uint8) 0x00); // 6 lgray = SDL_MapRGB(vfmt, (Uint8) 0xd0, (Uint8) 0xd0, (Uint8) 0xd0); // 7 gray = SDL_MapRGB(vfmt, (Uint8) 0xa6, (Uint8) 0xa6, (Uint8) 0xa6); // 8 lblue = SDL_MapRGB(vfmt, (Uint8) 0x00, (Uint8) 0x00, (Uint8) 0xff); // 9 lgreen = SDL_MapRGB(vfmt, (Uint8) 0x00, (Uint8) 0xff, (Uint8) 0x00); // 10 lcyan = SDL_MapRGB(vfmt, (Uint8) 0x54, (Uint8) 0xff, (Uint8) 0xff); // 11 lred = SDL_MapRGB(vfmt, (Uint8) 0xff, (Uint8) 0x00, (Uint8) 0x00); // 12 lmagenta = SDL_MapRGB(vfmt, (Uint8) 0xff, (Uint8) 0x54, (Uint8) 0xff); // 13 yellow = SDL_MapRGB(vfmt, (Uint8) 0xff, (Uint8) 0xff, (Uint8) 0x54); // 14 white = SDL_MapRGB(vfmt, (Uint8) 0xff, (Uint8) 0xff, (Uint8) 0xff); // 15 lyellow = SDL_MapRGB(vfmt, (Uint8) 0xff, (Uint8) 0xff, (Uint8) 0xc0); // 16 dyellow = SDL_MapRGB(vfmt, (Uint8) 0xa6, (Uint8) 0xa6, (Uint8) 0x00); // 17 pink = SDL_MapRGB(vfmt, (Uint8) 0xff, (Uint8) 0xa6, (Uint8) 0xa6); // 18 dblue = SDL_MapRGB(vfmt, (Uint8) 0x00, (Uint8) 0x00, (Uint8) /*0xa6*/0x80); // 19 dgreen = SDL_MapRGB(vfmt, (Uint8) 0x00, (Uint8) 0x80, (Uint8) 0x00); // 20}void widgetQuit(void){ timerData.vs = NULL;}// Blank the entire screen to blackvoid blankScreen(void){ SDL_Rect blank_area; blank_area.x = 0; blank_area.y = 0; blank_area.w = screen_width; blank_area.h = screen_height; SDL_FillRect(screen, (SDL_Rect *) &blank_area, 0);}// Mouse button down event has occurred on an AlertBox Cancel or OK button.// Set the response code for the parent widget (the AlertBox), and then// call its mousebuttondown function.void processAlertCallBack(SDL_Event *ev, BUTTON * btn){ ALERT *parent; char *c; void (*fptr)(SDL_Event *, void *); parent = btn->parent; c = btn->text; if (!strcmp(c, " Cancel ")) parent->response = ALERT_CANCEL; else if (!strcmp(c, " OK ")) parent->response = ALERT_OK; else parent->response = ALERT_NO_RESPONSE; fptr = parent->mdfunc; if (fptr) (*fptr)(ev, parent); updateScreen();}// Mouse button down event has occurred on an NoticeBox Close button.void processNoticeCallBack(SDL_Event *ev, BUTTON * btn){ NOTICE *parent; void (*fptr)(SDL_Event *, void *); parent = btn->parent; fptr = parent->mdfunc; if (fptr) (*fptr)(ev, parent); pushDownWidget(parent); updateScreen();}void attachCallBack(void *w, int type, void *func){ WIDGET *x; x = (WIDGET *) w; switch (type) { case SDL_MOUSEBUTTONDOWN: x->p.mdfunc = func; break; case SDL_MOUSEBUTTONUP: x->p.mufunc = func; break; case SDL_MOUSEMOTION: x->p.mmfunc = func; break; case SDL_KEYDOWN: x->p.kdfunc = func; break; case SDL_KEYUP: x->p.kufunc = func; break; case SLIDER_AUTO_CALLBACK: if (x->p.type == VSliderType || x->p.type == HSliderType) ((VSLIDER *) x)->adjfunc = func; break; }}void removeCallBack(void *w, int type){ WIDGET *x; x = (WIDGET *) w; switch (type) { case SDL_MOUSEBUTTONDOWN: x->p.mdfunc = NULL; break; case SDL_MOUSEBUTTONUP: x->p.mufunc = NULL; break; case SDL_MOUSEMOTION: x->p.mmfunc = NULL; break; case SDL_KEYDOWN: x->p.kdfunc = NULL; break; case SDL_KEYUP: x->p.kufunc = NULL; break; case SLIDER_AUTO_CALLBACK: if (x->p.type == VSliderType || x->p.type == HSliderType) ((VSLIDER *) x)->adjfunc = NULL; break; }}// A dummy callback function which does nothing at all.// This is available so that users can attach it to a// Label or other widget when they don't really want to// do anything except prevent underlying widgets from// executing their callbacks.void nullCallBack(void *w, ...){ // do nothing}// Return TRUE if child widget displays inside parent widgetbool childInParent(void *parent, void *child){ int x, y; WIDGET *p, *c; p = (WIDGET *) parent; c = (WIDGET *) child; x = c->p.x; y = c->p.y; if (x >= p->p.x && x <= p->p.x + p->p.w && y >= p->p.y && y <= p->p.y + p->p.h) return TRUE; return FALSE;}// Allocate a window structureWINDOW *newWindow(int x, int y, int w, int h, int fg, int bg, int hi, int lo){ WINDOW *win = (WINDOW *) malloc(sizeof(WINDOW)); win->type = WindowType; win->id = widget_id++; win->x = x; win->y = y; win->w = w; win->h = h; win->fg = fg; win->bg = bg; win->hi = hi; win->lo = lo; win->mdfunc = NULL; win->mufunc = NULL; win->mmfunc = NULL; win->kdfunc = NULL; win->kufunc = NULL; win->parent = NULL; win->list = NULL; return win;}// Allocate a menu structureMENU *newMenu(int x, int y, int w, int h, int fg, int bg, int hi, int lo){ MENU *menu = (MENU *) malloc(sizeof(MENU)); menu->type = MenuType; menu->id = widget_id++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -