#include #define DISPLAY_MAXBUF 9 #define DISPLAY_SURFACE_ID 1 void add_to_display(PtWidget_t *widget,char to_add) { PtSurface_t *surface; char *buf; size_t len; if(!(surface = PtFindSurface(widget,DISPLAY_SURFACE_ID))) return; if(!(buf = PtSurfaceGetData(widget,surface))) { char tmp[DISPLAY_MAXBUF + 1]; memset(tmp,0,sizeof(tmp)); if(PtSurfaceAddData(widget,surface,tmp,sizeof(tmp)) || !(buf = PtSurfaceGetData(widget,surface))) return; } len = strlen(buf); if(len == DISPLAY_MAXBUF) { memmove(buf,buf + 1,DISPLAY_MAXBUF - 1); len--; } buf[len] = to_add; PtDamageSurface(widget,surface); } int button_callback(PtWidget_t *widget,PtSurface_t *surface,PhEvent_t *event) { if(event->type == Ph_EV_BUT_PRESS) { PtSurfaceAddData(widget,surface,(void*)~0,0); PtDamageSurface(widget,surface); } else /* this must be a button release, but there are several types of releases - here we only concern ourselves with a couple */ switch(event->subtype) { case Ph_EV_RELEASE_PHANTOM: /* the surface that was presses always gets one of these, whether the actual release was within the surface or not. Therefore it's a good place to update to an unpressed state and redraw */ PtSurfaceRemoveData(widget,surface); PtDamageSurface(widget,surface); break; case Ph_EV_RELEASE_REAL: /* the surface that was released over gets this one, whether or not it was pressed to begin with. To mimic good button behaviour, this a good place to perform the associated action, IF it was the one that was pressed. Otherwise ignore this event. */ /* check to see if this was the last pressed surface */ if(PtWidgetActiveSurface(widget) == PtSurfaceId(surface)) add_to_display(widget,PtSurfaceId(surface)); else /* do not consume this event */ return(Pt_CONTINUE); /* don't do anything with the other subtypes */ default: return(Pt_CONTINUE); } return(Pt_END); } void button_draw(PtWidget_t *widget,PtSurface_t *surface,PhTile_t *damage) { PgColor_t *fg,*bg; PtArg_t args[2]; PhRect_t *rect = PtSurfaceRect(surface,NULL); char c; PtSetArg(&args[0],Pt_ARG_FILL_COLOR,&bg,0); PtSetArg(&args[1],Pt_ARG_COLOR,&fg,0); PtGetResources(widget,2,args); /* use surface data to indicate whether or not we're in a pressed state - if there is NO data, use this to indicate we're not pressed */ if(PtSurfaceGetData(widget,surface)) { /* we're pressed, invert color scheme */ PgSetTextColor(*bg); PgSetFillColor(*fg); } else { PgSetTextColor(*fg); PgSetFillColor(*bg); } PgSetStrokeColor(*fg); PgSetFont("TextFont09"); /* draw button background (just a circle) */ PgDrawEllipse(&rect->ul,&rect->lr,Pg_DRAW_FILL_STROKE | Pg_EXTENT_BASED); /* draw number (which we've conveniently stored as our id!) */ c = PtSurfaceId(surface); PgDrawTextArea((char const*)&c,sizeof(c),rect,Pg_TEXT_CENTER | Pg_TEXT_MIDDLE); } void button_calc(PtWidget_t *widget,PtSurface_t *surface,uchar_t post) { if(post) { /* only calculate our geometry after our parent widget has */ PhDim_t dim; int row,col; PhRect_t *rect = PtSurfaceRect(surface,NULL); PhRectDim(PtGetCanvas(widget),&dim); col = (PtSurfaceId(surface) - '1') % 3; row = ((PtSurfaceId(surface) - '1') / 3) + 1; dim.w /= 3; dim.h /= 4; rect->ul.x = (dim.w * col) + 2; rect->ul.y = (dim.h * row) + 2; rect->lr.x = (dim.w * (col + 1)) - 3; rect->lr.y = (dim.h * (row + 1)) - 3; } } void display_draw(PtWidget_t *widget,PtSurface_t *surface,PhTile_t *damage) { char const *buf; PgColor_t *fg,*bg; PtArg_t args[2]; PhRect_t *rect = PtSurfaceRect(surface,NULL); PtSetArg(&args[0],Pt_ARG_FILL_COLOR,&bg,0); PtSetArg(&args[1],Pt_ARG_COLOR,&fg,0); PtGetResources(widget,2,args); PgSetStrokeColor(*fg); PgDrawRect(rect,Pg_DRAW_STROKE); if(buf = PtSurfaceGetData(widget,surface)) { PgSetFont("FixedFont09"); PgSetTextColor(*fg); PgDrawTextArea(buf,strlen(buf),rect,Pg_TEXT_RIGHT | Pg_TEXT_MIDDLE); } } void display_calc(PtWidget_t *widget,PtSurface_t *surface,uchar_t post) { if(post) { /* only calculate our geometry after our parent widget has */ PhDim_t dim; PhRect_t *rect = PtSurfaceRect(surface,NULL); PhRectDim(PtGetCanvas(widget),&dim); rect->ul.x = 2; rect->ul.y = 2; rect->lr.x = dim.w - 3; rect->lr.y = (dim.h / 4) - 3; } } int main(int argc,char *argv[]) { PtWidget_t *window; PtArg_t args[3]; PhArea_t area = { { 100,100 },{ 120,120 } }; PtSetArg(&args[0],Pt_ARG_AREA,&area,0); PtSetArg(&args[1],Pt_ARG_WINDOW_TITLE,"Keypad",0); PtSetArg(&args[2],Pt_ARG_WINDOW_RENDER_FLAGS,0,Ph_WM_RENDER_COLLAPSE | Ph_WM_RENDER_MAX | Ph_WM_RENDER_MIN); if(window = PtAppInit(NULL,&argc,argv,3,args)) { int i; /* create surface for numeric display */ if(!PtCreateSurface( window, /* parent widget */ DISPLAY_SURFACE_ID, /* use known id */ 0, /* no flags needed */ Pt_SURFACE_RECT, /* for rectangle display */ NULL, /* let lib allocate points for me */ 0, /* sensitive to no events */ NULL, /* no events, therefore no callback */ display_draw, /* display draw function */ display_calc)) /* display geometry calculation */ { perror(argv[0]); return(EXIT_FAILURE); } /* create one button each for numbers '1' through '9' */ for(i = '1';i <= '9';i++) if(!PtCreateSurface( window, /* parent widget */ i, /* ctrl surface numeric id */ 0, /* no flags needed */ Pt_SURFACE_ELLIPSE, /* for circle buttons */ NULL, /* let lib allocate points for me */ Ph_EV_BUT_PRESS | Ph_EV_BUT_RELEASE, /* sensitive to button presses and releases */ button_callback, /* button press/release callback */ button_draw, /* button draw function */ button_calc)) /* button geometry calculation */ { perror(argv[0]); return(EXIT_FAILURE); } } else { perror(argv[0]); return(EXIT_FAILURE); } PtRealizeWidget(window); PtMainLoop(); return(EXIT_SUCCESS); }