diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/addrs.c | 27 | ||||
| -rw-r--r-- | src/addrs.h | 15 | ||||
| -rw-r--r-- | src/edbox.c | 138 | ||||
| -rw-r--r-- | src/edbox.h | 14 | ||||
| -rw-r--r-- | src/screen.c | 222 | ||||
| -rw-r--r-- | src/screen.h | 103 |
6 files changed, 519 insertions, 0 deletions
diff --git a/src/addrs.c b/src/addrs.c new file mode 100644 index 0000000..8c4ad1b --- /dev/null +++ b/src/addrs.c @@ -0,0 +1,27 @@ +#include "addrs.h" + +u8 *dlist = u8p(DLIST_ADDR); +u16 *dlist_top_lms = u16p(0xa404); +u16 *dlist_bottom_lms = u16p(0xa41e); +u8 *status_box = u8p(0xa425); /* 80 bytes */ +u8 *edit_box = u8p(0xa475); /* 160 bytes */ + +u8 *screen_addrs[7] = { + u8p(0xa538), + u8p(0xa8d0), + u8p(0xac68), + u8p(0xb000), + u8p(0xb398), + u8p(0xb730), + u8p(0xbac8) +}; + +u8 *screen_botlines[7] = { + u8p(0xa8a8), + u8p(0xac40), + u8p(0xafd8), + u8p(0xb370), + u8p(0xb708), + u8p(0xbaa0), + u8p(0xbe38) +}; diff --git a/src/addrs.h b/src/addrs.h new file mode 100644 index 0000000..6d44a68 --- /dev/null +++ b/src/addrs.h @@ -0,0 +1,15 @@ +#define FONT_ADDR_HI 0xa0 +#define DLIST_ADDR 0xa400 + +#define u8 unsigned char +#define u8p(x) ((unsigned char *)x) +#define u16 unsigned int +#define u16p(x) ((unsigned int *)x) + +extern u8 *dlist; +extern u16 *dlist_top_lms; +extern u16 *dlist_bottom_lms; +extern u8 *status_box; +extern u8 *edit_box; +extern u8 *screen_addrs[7]; +extern u8 *screen_botlines[7]; diff --git a/src/edbox.c b/src/edbox.c new file mode 100644 index 0000000..f1c77d1 --- /dev/null +++ b/src/edbox.c @@ -0,0 +1,138 @@ +#include <atari.h> +#include <conio.h> +#include <string.h> +#include "addrs.h" +#include "screen.h" +#include "edbox.h" + +/* TODO: tab completion */ + +// static int edbox_visible = 0; /* don't think we'll ever need it */ +static u16 edbox_pos; /* range 0 to EDBOX_SIZE - 1 */ + +void (*edbox_callback)(void); + +static void hide_cursor(void) { + edit_box[edbox_pos] &= 0x7f; +} + +static void show_cursor(void) { + edit_box[edbox_pos] |= 0x80; +} + +void edbox_clear(void) { + memset(edit_box, 0, EDBOX_SIZE); + edbox_pos = 0; + show_cursor(); +} + +void edbox_show(void) { + u16 addr; + + if(edbox_pos < 80) + addr = (u16)edit_box; + else + addr = (u16)edit_box + edbox_pos - 79; + + scr_waitvcount(116); + + *dlist_bottom_lms = addr; +} + +void edbox_hide(void) { + scr_refresh(); +} + +void edbox_putc(char c) { + if(!c) + return; /* no inserting nulls */ + if((c != CH_EOL) && (edbox_pos == EDBOX_SIZE - 1)) + return; + edit_box[edbox_pos++] = c; + edbox_show(); +} + +static void special_keystroke(char c) { + OS.ch = 0xff; + edbox_putc(c); +} + +static void backspace(void) { + if(!edbox_pos) return; + edit_box[--edbox_pos] = 0; + edbox_show(); +} + +static void del_word(void) { +} + +static void normal_keystroke(void) { + char c; + + c = cgetc(); + + switch(c) { + case CH_EOL: + edbox_putc(c); + if(edbox_callback) + (*edbox_callback)(); + /* fall thru */ + case CH_CLR: + edbox_hide(); + /* fall thru */ + case CH_DELLINE: + case 0x15: /* ^U */ + edbox_clear(); + break; + case CH_DEL: + backspace(); + break; + case 0x17: /* ^W */ + del_word(); + break; + default: + edbox_putc(c); + break; + } +} + +void edbox_keystroke(void) { + char c; + + hide_cursor(); + edbox_show(); + + OS.invflg = c = 0; + + /* XXX: these keys don't click. */ + switch(OS.ch) { + case 0xa0: /* key: ctrl [ */ + c = 0x7b; /* ascii: { */ + break; + case 0xa2: /* key: ctrl ] */ + c = 0x7d; /* ascii: } */ + break; + case 0x1c: /* key: ESC */ + c = 0x60; /* ascii: ` */ + break; + case 0x5c: /* key: shift ESC */ + case 0x9c: /* key: ctrl ESC */ + c = 0x7e; /* ascii: ~ */ + break; + case 0x27: /* atari key */ + case 0x67: /* ...w/shift */ + case 0x97: /* ...w/ctrl */ + return; /* ignore it! */ + break; + default: + break; + } + + if(c) { + special_keystroke(c); + } else { + normal_keystroke(); + } + + show_cursor(); +} diff --git a/src/edbox.h b/src/edbox.h new file mode 100644 index 0000000..ad70cc6 --- /dev/null +++ b/src/edbox.h @@ -0,0 +1,14 @@ +#include "addrs.h" + +/**** public API ****/ + +#define EDBOX_SIZE 160 + +void edbox_clear(void); +void edbox_show(void); +void edbox_hide(void); +void edbox_putc(char c); +void edbox_keystroke(void); + +/* called when the user presses Enter */ +extern void (*edbox_callback)(void); diff --git a/src/screen.c b/src/screen.c new file mode 100644 index 0000000..7f34331 --- /dev/null +++ b/src/screen.c @@ -0,0 +1,222 @@ +#include <atari.h> +#include <string.h> + +#include "addrs.h" +#include "screen.h" + +#define SDLST ((u16 *)0x0230) + +char scr_active[MAX_SCREENS]; + +/* the screen that's currently displaying */ +char scr_current; + +static char scr_names[7][32]; +static char scr_topics[7][40]; + +static char xpos; + +void scr_waitvcount(u8 c) { + while(ANTIC.vcount < c) + /* NOP */; +} + +static void scr_clear(char s) { + memset(screen_addrs[s], 0, SCREEN_SIZE); + memset(scr_names[s], 0, 32); + memset(scr_topics[s], 0, LINE_SIZE); +} + +static void scr_scroll(char s) { + memmove(screen_addrs[s], screen_addrs[s] + 40, 880); + memset(screen_botlines[s], 0, 40); +} + +void scr_init(void) { + int i, old_dma; + + old_dma = OS.sdmctl; + OS.sdmctl = 0; + scr_waitvcount(112); /* after the last GR.0 line */ + *SDLST = DLIST_ADDR; + OS.chbas = FONT_ADDR_HI; + + for(i = 0; i < MAX_SCREENS; i++) { + scr_clear(i); + scr_active[i] = SCR_UNUSED; + } + + strcpy(scr_names[0], "[server]"); + strcpy(scr_names[1], "[private]"); + scr_active[0] = scr_active[1] = SCR_INACTIVE; + + OS.sdmctl = old_dma; + + scr_display(0); +} + +char scr_create(const char *name, char display) { + int i; + + for(i = 0; i < MAX_SCREENS; i++) { + if(scr_active[i] == SCR_UNUSED) { + strcpy(scr_names[i], name); + scr_active[i] = SCR_INACTIVE; + scr_topics[i][0] = '\0'; + if(display) + scr_display(i); + else + scr_display(scr_current); + return i; + } + } + + // scr_print(SCR_CURR, "Can't create window (all in use)\n"); + return 0xff; +} + +void scr_destroy(char s) { + /* <2 because screens 0 and 1 (server and private) cannot be destroyed */ + if(s < 2 || s >= MAX_SCREENS) + return; + + scr_active[s] = SCR_UNUSED; + if(scr_current == s) + scr_display(0); +} + +void scr_set_topic(char s, const char *topic) { + strncpy(scr_topics[s], topic, 40); +} + +void scr_display(char s) { + if(s >= MAX_SCREENS) + return; + + /* leave this out, for testing + if(scr_active[s] == SCR_UNUSED) + return; + */ + + scr_active[s] = SCR_INACTIVE; + scr_current = s; + + scr_waitvcount(112); + *dlist_top_lms = (u16)screen_addrs[s]; + + scr_show_status(s); +} + +void scr_show_status(char s) { + int i; + char *p, sc; + + status_box[0] = s + 177; /* inverse number */ + status_box[1] = ':'; + strncpy(status_box + 2, scr_names[s], 32); + strncpy(status_box + 40, scr_topics[s], 40); + + p = status_box + 33; + for(i = 0; i < MAX_SCREENS; i++) { + switch(scr_active[i]) { + case SCR_ACTIVE: + sc = 128 | ('1' + i); break; + case SCR_INACTIVE: + sc = '1' + i; break; + default: + sc = ' '; + } + *p++ = sc; + } + + scr_waitvcount(112); + *dlist_bottom_lms = (u16)status_box; +} + +void scr_refresh(void) { + scr_display(scr_current); +} + +char scr_getbyname(const char *name) { + char i; + + for(i = 2; i < MAX_SCREENS; i++) { + if(strcasecmp(name, scr_names[i]) == 0) + return i; + } + + return 0; +} + +/* TODO: skip color codes (start with 0x03 or 0x04). + if we're going to ever support utf-8, decode it here... + also, 0x16 is supposed to be reverse video. not widely used/supported. + eventually, this will be rewritten in asm anyway. */ +void scr_putc(char s, char c) { + u8 *dest; + static char bold = 0; + + if(s == SCR_CURR) + s = scr_current; + + if(c == '\n') { + bold = 0; + if(!xpos) + return; + xpos = 40; + return; + } + + if(xpos == 40) { + scr_scroll(s); + xpos = 0; + } + + dest = screen_botlines[s] + xpos; + + if(c & 0x80) { + /* utf-8 (or maybe latin-1), we don't support it yet */ + c = 0xbf; /* inverse ? */ + } else if(c == 0x02) { + bold = !bold; + return; + } else if(c == 0x1d) { + /* italics */ + c = '/'; + } else if(c == 0x1e) { + /* strikethru */ + c = '-'; + } else if(c == 0x1f) { + /* underline */ + c = '_'; + } else if(c == 0x0f) { + /* all formatting off */ + bold = 0; + return; + } else if(c < 0x20) { + /* unsupported control character */ + c += 192; + } + + if(bold) c |= 0x80; + + *dest = c; + xpos++; +} + +void scr_print(char s, const char *text) { + while(*text) { + scr_putc(s, *text); + if(*text == '\n') + break; + text++; + } + scr_activate(s); +} + +void scr_activate(char s) { + if(s != scr_current) { + scr_active[s] = SCR_ACTIVE; + scr_show_status(scr_current); + } +} diff --git a/src/screen.h b/src/screen.h new file mode 100644 index 0000000..5762009 --- /dev/null +++ b/src/screen.h @@ -0,0 +1,103 @@ +#include "addrs.h" + +#define MAX_SCREENS 7 +#define LINE_SIZE 40 +#define SCREEN_SIZE 920 +#define BOTTOM_LINE_OFFS 880 + +#define SCR_UNUSED 0 +#define SCR_INACTIVE 1 +#define SCR_ACTIVE 2 + +#define SCR_CURR 0xff + +/**** public API ****/ + +/* the screen that's currently displaying */ +extern char scr_current; + +/* which screens are "active". the screen being displayed is + never active. any screen that's not visible that's had anything + written to it gets marked active. switching the display to an + active screen clears its active flag. */ +extern char scr_active[MAX_SCREENS]; + +/* call before using any of the other functions. sets up the + display list, clears all screen memory, selects screen 0 + for display. */ +void scr_init(void); + +/* creates a screen, if possible. we only get 7; attempts to create + more that that will return -1. on success, returns the screen + number (0-6). the name gets copied to the 1st line of the screen's + status box. + if display is true, the new screen displays. otherwise it's created + "in the background". + */ +char scr_create(const char *name, char display); + +/* destroys a screen (frees up its slot). */ +void scr_destroy(char s); + +/* sets the topic for a screen (the 2nd line of the status box). + this can't just be another argument to scr_create() because we + don't know the topic yet when we create a screen (also, the + server and msgs windows don't have topics anyway). */ +void scr_set_topic(char s, const char *topic); + +/* switch display to screen s. updates the display list. clears + s's active flag. calls scr_show_status(). */ +void scr_display(char s); + +/* XXX: does this need to be public? */ +void scr_show_status(char s); + +/* calls scr_display() on the currently-visible screen. + called by the edit box code, when closing the edit box (user has + pressed Enter or aborted the message). */ +void scr_refresh(void); + +/* given a channel name, find its screen. if there's no match, + returns 0 (the server messages screen) */ +char scr_getbyname(const char *name); + +/* print one character to a screen. handles scrolling. will not + print an EOL at column 0 (just ignores it). */ +void scr_putc(char s, char c); + +/* print text to a screen. handles scrolling. this + doesn't have to be the screen being displayed, of course; + if it's not, it gets marked as active. */ +void scr_print(char s, const char *text); + +/* set a screen's status to active, if it's not the currently-displayed + one. scr_print() sets it already, but anything that uses scr_putc() + will have to call this. */ +void scr_activate(char s); + +/* XXX: this really should be in a utils.c or common.c... */ +void scr_waitvcount(u8 c); + +/**** end of public API ****/ + +/* notes: + +If a character gets printed to the bottom right corner of a screen, +it *doesn't* scroll yet. It will, the next time a character is printed +to that screen. + +This thing uses a modified font that's in ASCII order rather than +Atari screencode order. So "printing" just means copying... except +for IRC formatting codes. + +scr_print() has to handle formatting: at least it should print inverse +video for either bold or italic. It will print incoming inverse +video as-is; it's the caller's responsibility to replace unprintable +characters (e.g. any char >= 128 might become an inverse question +mark). This has to happen because nick highlighting will use inverse +video. + +Also, scr_print() should eventually be smart enough to strip out color +codes. + +*/ |
