jcs
/detritus
/amendments
/33
gopher: Draw icons for menu items using TextView's new BitMap support
jcs made amendment 33 about 1 year ago
--- browser.c Mon Nov 11 23:31:50 2024
+++ browser.c Thu Nov 14 14:30:59 2024
@@ -58,6 +58,7 @@ void browser_atexit(struct focusable *focusable);
void browser_go(struct browser *browser, short dir);
page_handle browser_create_page(struct browser *browser, char *uristr);
void browser_draw_status(struct browser *browser);
+struct TVStyle * browser_build_tvstyle(struct browser *browser);
void browser_finished_loading(struct browser *browser);
void browser_follow_redir(struct browser *browser);
void browser_stop_loading_page(struct browser *browser);
@@ -797,14 +798,13 @@ browser_draw_status(struct browser *browser)
DrawText(browser->status_text, 0, browser->status_length);
}
-size_t
-browser_print(struct browser *browser, const char *str, size_t len,
- bool newline)
+struct TVStyle *
+browser_build_tvstyle(struct browser *browser)
{
- struct TVStyle style;
- struct browser_link *link;
- size_t n, nlines;
+ static struct TVStyle style;
+ memset(&style, 0, sizeof(style));
+
style.font = BROWSER_FONT;
style.size = BROWSER_FONT_SIZE;
style.style = 0;
@@ -829,9 +829,33 @@ browser_print(struct browser *browser, const char *str
else if (browser->style & STYLE_H3)
style.size += 2;
+ return &style;
+}
+
+size_t
+browser_print_bitmap(struct browser *browser, BitMap *icon,
+ FontInfo *sizing)
+{
+ struct TVStyle *style;
+
+ style = browser_build_tvstyle(browser);
+ style->font_info = *sizing;
+
+ return !!TVAppendBitMap(browser->output_tv, icon, style);
+}
+
+size_t
+browser_print(struct browser *browser, const char *str, size_t len,
+ bool newline)
+{
+ struct TVStyle *style;
+ size_t n, nlines;
+
+ style = browser_build_tvstyle(browser);
+
nlines = (*(browser->output_tv))->nlines;
- (newline ? TVAppendLine : TVAppend)(browser->output_tv, &style,
+ (newline ? TVAppendLine : TVAppend)(browser->output_tv, style,
(char *)str, len);
if ((*(browser->output_tv))->nlines != nlines)
--- browser.h Mon Nov 11 23:13:28 2024
+++ browser.h Wed Nov 13 14:17:46 2024
@@ -131,6 +131,8 @@ size_t browser_print_link(struct browser *browser, con
size_t url_len, const char *title, size_t title_len, bool newline);
size_t browser_print(struct browser *browser, const char *str, size_t len,
bool newline);
+size_t browser_print_bitmap(struct browser *browser, BitMap *icon,
+ FontInfo *sizing);
void browser_recalc_scrollbar(struct browser *browser);
struct page * browser_grow_page_content(struct page *page, size_t len);
void browser_go_uri(struct browser *browser, char *uristr);
--- gopher.c Mon Nov 11 23:12:46 2024
+++ gopher.c Wed Nov 13 14:24:43 2024
@@ -20,13 +20,28 @@
#include "detritus.h"
-#define GOPHER_PORT 70
+#define GOPHER_PORT 70
+#define GOPHER_ICON_SICN_ID 1024
+#define GOPHER_ICON_TEXT_ID 0
+#define GOPHER_ICON_FOLDER_ID 1
+#define GOPHER_ICON_MACARCHIVE_ID 2
+#define GOPHER_ICON_DOSARCHIVE_ID 3
+#define GOPHER_ICON_UNKNOWN_ID 4
+#define GOPHER_ICON_SEARCH_ID 5
+#define GOPHER_ICON_SOUND_ID 6
+#define GOPHER_ICON_IMAGE_ID 7
+#define GOPHER_ICON_DOC_ID 8
+
/* printing line-by-line is slow, so only recalc every n lines */
-#define RECALC_EVERY_N_LINES 25
+#define RECALC_EVERY_N_LINES 25
static const char showable_types[] = "013i";
+struct gopher_page {
+ Handle sicn;
+};
+
bool gopher_accept_uri(struct URI *uri);
bool gopher_request_init(page_handle pageh);
bool gopher_process(page_handle pageh);
@@ -53,6 +68,7 @@ bool
gopher_request_init(page_handle pageh)
{
struct page *page = *pageh;
+ struct gopher_page *gopher;
size_t selector_len, output_len;
char *filename, *output;
@@ -82,15 +98,32 @@ gopher_request_init(page_handle pageh)
snprintf(output, output_len + 1, "%s\r\n",
selector_len ? page->uri->path + 2 : "");
+ gopher = xmalloc(sizeof(struct gopher_page));
+ if (gopher == NULL) {
+ xfree(&output);
+ warn("Out of memory");
+ return false;
+ }
+ gopher->sicn = Get1Resource('SICN', GOPHER_ICON_SICN_ID);
+ if (gopher->sicn == NULL) {
+ xfree(&output);
+ xfree(&gopher);
+ warn("Can't find Gopher SICN");
+ return false;
+ }
+
page->request = request_connect(page->browser, page->uri->hostname,
page->uri->port, false, 0);
if (page->request == NULL) {
+ ReleaseResource(gopher->sicn);
+ xfree(&gopher);
xfree(&output);
return false;
}
page->request->output_len = output_len;
page->request->output = output;
-
+ page->handler_cookie = gopher;
+
/* XXX: try to detect server responding with "3" for error? */
if (strchr(showable_types, page->content_type[0]) == NULL) {
@@ -208,14 +241,20 @@ static void
gopher_print_menu(struct page *page, char *line, size_t len)
{
static char uri[URI_MAX_STR_LEN + 1], prefix[5];
+ struct gopher_page *gopher;
+ BitMap icon;
+ FontInfo sizing;
char type, *label, *selector = NULL, *hostname = NULL;
size_t tlen;
unsigned short port = 0;
+ short icon_off = -1;
long n;
type = line[0];
label = line + 1;
+ gopher = (struct gopher_page *)page->handler_cookie;
+
for (n = 1; n < len; n++) {
if (line[n] != '\t')
continue;
@@ -239,8 +278,86 @@ gopher_print_menu(struct page *page, char *line, size_
browser_print(page->browser, label, strlen(label), true);
break;
default:
- snprintf(prefix, sizeof(prefix), "[%c] ", type);
- browser_print(page->browser, prefix, 4, false);
+ switch (type) {
+ case '0':
+ /* text file */
+ icon_off = GOPHER_ICON_TEXT_ID;
+ break;
+ case '1':
+ /* submenu */
+ icon_off = GOPHER_ICON_FOLDER_ID;
+ break;
+ case '3':
+ /* error page */
+ icon_off = GOPHER_ICON_UNKNOWN_ID;
+ break;
+ case '5':
+ /* dos */
+ icon_off = GOPHER_ICON_DOSARCHIVE_ID;
+ break;
+ case '4':
+ /* mac binhex */
+ icon_off = GOPHER_ICON_MACARCHIVE_ID;
+ break;
+ case '7':
+ /* search */
+ icon_off = GOPHER_ICON_SEARCH_ID;
+ break;
+ case '2':
+ /* ccso nameserver? */
+ case '+':
+ /* mirror? */
+ case '6':
+ /* uuencoded */
+ case '8':
+ /* telnet */
+ case '9':
+ /* binary file */
+ case 'T':
+ /* telnet 3270 */
+ case 'd':
+ /* doc */
+ case 'h':
+ /* html */
+ case 'r':
+ /* rtf */
+ case 'P':
+ /* pdf */
+ case 'X':
+ /* xml */
+ icon_off = GOPHER_ICON_DOC_ID;
+ break;
+ case 'g':
+ /* gif */
+ case 'I':
+ /* image */
+ case 'p':
+ /* png */
+ case ':':
+ /* bitmap */
+ case ';':
+ /* movie */
+ icon_off = GOPHER_ICON_IMAGE_ID;
+ break;
+ case '<':
+ /* sound */
+ icon_off = GOPHER_ICON_SOUND_ID;
+ break;
+ default:
+ icon_off = GOPHER_ICON_UNKNOWN_ID;
+ }
+
+ HLock(gopher->sicn);
+ icon.baseAddr = (char *)*(gopher->sicn) + (icon_off * 32);
+ icon.rowBytes = 2;
+ SetRect(&icon.bounds, 0, 0, 12, 12);
+
+ sizing.ascent = 10;
+ sizing.descent = 2;
+ sizing.widMax = 20;
+ browser_print_bitmap(page->browser, &icon, &sizing);
+
+ HUnlock(gopher->sicn);
if (type == 'h' && strncmp(selector, "URL:", 4) == 0)
tlen = strlcpy(uri, selector + 4, sizeof(uri));