aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/addrs.c27
-rw-r--r--src/addrs.h15
-rw-r--r--src/edbox.c138
-rw-r--r--src/edbox.h14
-rw-r--r--src/screen.c222
-rw-r--r--src/screen.h103
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.
+
+*/