/* Simple terminal using GraphApp * * Copyright (c) ITB CompuPhase, 2004-2011 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * * Version: $Id: term_ga.c 4523 2011-06-21 15:03:47Z thiadmer $ */ #include #include #include #include #include #include #include "term_ga.h" #define NUM_COLUMNS 80 #define NUM_LINES 30 #define KEYQUEUE_SIZE 32 #define BUFFERSIZE 2048 static App *app = NULL; static Window *win = NULL; static Font *font = NULL; static TCHAR *lines = NULL; static unsigned long keyqueue[KEYQUEUE_SIZE]; static int keyq_start,keyq_end; static int csrx = 0, csry = 0; static int autowrap = 0; static unsigned char attrib = 0x07; static void window_redraw(Window *w, Graphics *g) { Rect r; Point p; int l, h; int length; char *buffer; assert(lines != NULL); /* Each wide char is encoded in at most 6 UTF8 characters. For the Base Plane, * 3 UTF8 characters per Unicode character is enough */ buffer = malloc((6 * NUM_COLUMNS + 1) * sizeof(char)); if (buffer != NULL) { r = get_window_area(w); set_rgb(g, rgb(240,240,240)); //??? attrib fill_rect(g, r); set_rgb(g, rgb(0,0,0)); //??? attrib set_font(g, font); set_text_direction(g, LR_TB); p = pt(0,0); h = font_height(font); for (l = 0; l < NUM_LINES; l++) { #if defined _UNICODE /* convert the line to UTF8 */ int c; char *ptr; for (c = 0, ptr = buffer; c < NUM_COLUMNS; c++) amx_UTF8Put(ptr, &ptr, 6, lines + l * NUM_COLUMNS + c); *ptr = '\0'; length = (int)(ptr - buffer); #else /* assume line is ASCII */ memcpy(buffer, lines + l * NUM_COLUMNS, NUM_COLUMNS); buffer[NUM_COLUMNS] = '\0'; length = NUM_COLUMNS; #endif /* draw the line */ draw_utf8(g, p, buffer, length); p.y += h; if (p.y > r.height) break; } /* if */ free(buffer); } /* if */ } /* dx = in columns, dy = in lines */ static void scroll_window(int dx, int dy) { Graphics *g; Rect r; Point p; /* a negative value scrolls up */ assert(lines != NULL); if (dy < 0) { assert(-dy < NUM_LINES); memmove(lines,lines-dy*NUM_COLUMNS,(NUM_LINES+dy)*NUM_COLUMNS*sizeof(TCHAR)); memset(lines+(NUM_LINES+dy)*NUM_COLUMNS*sizeof(TCHAR), __T(' '), -dy*NUM_COLUMNS); } else if (dy > 0) { assert(dy < NUM_LINES); memmove(lines+dy*NUM_COLUMNS,lines,(NUM_LINES-dy)*NUM_COLUMNS*sizeof(TCHAR)); memset(lines, __T(' '), dy*NUM_COLUMNS); } /* if */ csry += dy; if (csry < 0) csry = 0; if (csry >= NUM_LINES) csry=NUM_LINES - 1; assert(font != NULL); dx *= font_width(font, "x", 1); dy *= font_height(font); g = get_window_graphics(win); r = get_window_area(win); p = pt(r.x + dx, r.y + dy); copy_rect(g, p, g, r); if (dy > 0) { /* moving window contents downwards */ redraw_rect(win, rect(0,0,r.width,dy)); } else if (dy < 0) { /* moving window contents upwards */ redraw_rect(win, rect(0,r.height+dy,r.width,0-dy)); } /* if */ if (dx > 0) { /* moving window contents to the right */ redraw_rect(win, rect(0,0,dx,r.height)); } else if (dx < 0) { /* moving window contents to the left */ redraw_rect(win, rect(r.width+dx,0,0-dx,r.height)); } /* if */ del_graphics(g); } static void refresh_screen(int top, int bottom) { Rect r; int h; if (top != bottom) { assert(win != NULL); r = get_window_area(win); assert(font != NULL); h = font_height(font); redraw_rect(win, rect(0, top * h, r.width, (bottom - top) * h)); } /* if */ //??? set to draw a caret } #if 0 static void window_fkey_action(Window *w, unsigned long key) { } #endif static void window_key_action(Window *w, unsigned long key) { #if defined __WIN32__ || defined _WIN32 || defined WIN32 /* translate the Enter key from '\n' (GraphApp convention) to '\r' * (AMXCONS convention when running under Microsoft Windows) */ if (key == '\n') key = '\r'; #endif if ((keyq_end+1)%KEYQUEUE_SIZE==keyq_start) { beep(app); } else { keyqueue[keyq_end]=key; keyq_end=(keyq_end+1)%KEYQUEUE_SIZE; } /* if */ } static void window_close(Window *w) { /* we cannot delete the window on this notification (GraphApp refers to it * on return from the function), so we just mark the global variable * as invalid */ win = NULL; } int createconsole(int argc, char *argv[]) { if (win != NULL) return 1; if (app != NULL) /* delete existing partial data structures */ deleteconsole(); lines = malloc(NUM_LINES*NUM_COLUMNS*sizeof(TCHAR)); if (lines == NULL) return 0; memset(lines, __T(' '), NUM_LINES * NUM_COLUMNS); app = new_app(argc, argv); if (app == NULL) { deleteconsole(); return 0; } /* if */ font = new_font(app, "unifont", PLAIN | PORTABLE_FONT, 16); if (font == NULL) font = new_font(app, "courier", PLAIN | NATIVE_FONT, 16); if (font == NULL) font = find_default_font(app); if (font == NULL) { deleteconsole(); return 0; } /* if */ win = new_window(app, rect(0,0, NUM_COLUMNS*font_width(font,"x",1), NUM_LINES*font_height(font)), "Pawn console", TITLEBAR|CLOSEBOX|MAXIMIZE|MINIMIZE|CENTRED); on_window_redraw(win, window_redraw); on_window_close (win, window_close); on_window_key_down(win, window_key_action); /* normal keys (including CR) */ show_window(win); /* handle any pending events */ while (do_event(app)) /* nothing */; csrx = 0; csry = 0; autowrap = 0; attrib = 0x07; return 1; } int deleteconsole(void) { if (font != NULL) { del_font(font); font = NULL; } /* if */ if (app != NULL) { del_app(app); app = NULL; } /* if */ if (lines != NULL) { free(lines); lines = NULL; } /* if */ win = NULL; return 1; } int amx_putstr(const TCHAR *string) { if (createconsole(0, NULL)) { int pos, i; pos=csry * NUM_COLUMNS + csrx; assert(lines!=NULL); for (i=0; string[i]!=__T('\0'); i++) { if (csry=NUM_LINES) scroll_window(0, -1); pos=csry * NUM_COLUMNS + csrx; } else if (string[i]==__T('\b')) { if (csrx>0) { csrx--; pos--; lines[pos]=__T(' '); //??? lines[pos+1]=attrib; } /* if */ } else { lines[pos]=string[i]; //??? lines[pos+1]=attrib; pos++; csrx++; if (csrx>=NUM_COLUMNS && autowrap) { csrx=0; csry++; if (csry>=NUM_LINES) scroll_window(0, -1); pos=csry * NUM_COLUMNS + csrx; } /* if */ } /* if */ } /* if */ } /* for */ refresh_screen(csry,csry+1); } /* if */ return 0; } int amx_printf(const TCHAR *format,...) { int cnt; TCHAR buffer[BUFFERSIZE]; va_list argptr; va_start(argptr,format); cnt=_vstprintf(buffer,format,argptr); va_end(argptr); amx_putstr(buffer); return cnt; } int amx_putchar(int c) { if (createconsole(0, NULL)) { if (csry=NUM_LINES) scroll_window(0, -1); } else if (c==__T('\b')) { if (csrx>0) { csrx--; pos--; lines[pos]=__T(' '); //??? lines[pos+1]=attrib; } /* if */ } else { lines[pos]=(TCHAR)c; //??? lines[pos+1]=attrib; csrx++; if (csrx>=NUM_COLUMNS && autowrap) { csrx=0; csry++; if (csry>=NUM_LINES) scroll_window(0, -1); } /* if */ } /* if */ refresh_screen(csry,csry+1); } /* if */ } /* if */ return 1; } int amx_fflush(void) { return 1; } int amx_kbhit(void) { if (createconsole(0, NULL)) return keyq_start!=keyq_end; return 0; } int amx_getch(void) { int c=-1; if (createconsole(0, NULL)) { int cursor=0; if (keyq_start==keyq_end) { amx_putchar(__T('_')); /* must wait for character, so put pseudo-cursor */ cursor=1; } /* if */ while (keyq_start==keyq_end && app!=NULL) { wait_event(app); do_event(app); } /* while */ c=(int)keyqueue[keyq_start]; if (c=='\n') c='\r'; /* enter key must be '\r' for Pawn */ keyq_start=(keyq_start+1)%KEYQUEUE_SIZE; if (cursor) amx_putchar(__T('\b')); /* remove speudo-cursor */ } /* if */ return c; } TCHAR *amx_gets(TCHAR *string,int size) { int c=-1,num=0; if (createconsole(0, NULL)) { while (num+10) string[--num]=__T(' '); } else { string[num++]=(TCHAR)c; } /* if */ amx_putchar(c); /* echo the character read */ } /* while */ if (num0 && x<=NUM_COLUMNS) csrx=x-1; if (y>0 && y<=NUM_LINES) csry=y-1; refresh_screen(0, 0); /* only to set the cursor at the correct location */ } /* if */ } void amx_wherexy(int *x,int *y) { if (createconsole(0, NULL)) { if (x!=NULL) *x=csrx+1; if (y!=NULL) *y=csry+1; } /* if */ } unsigned int amx_setattr(int foregr,int backgr,int highlight) { int prev=0; if (createconsole(0, NULL)) { int f,b,h; f=attrib & 0x07; b=(attrib >> 4) & 0x0f; h=(attrib & 0x08) ? 1 : 0; prev=(b << 8) | f | (h << 15); if (foregr>=0 && foregr<8) f=foregr; if (backgr>=0 && backgr<8) b=backgr; if (highlight>=0) h=highlight!=0; attrib=(TCHAR)((b << 4) | f | (h << 3)); } /* if */ return prev; } void amx_console(int columns, int lines, int flags) { createconsole(0, NULL); /* columns and lines are currently not supported */ }