From bbc0d4d5c89db477178ef05e5cbfba2856713e06 Mon Sep 17 00:00:00 2001 From: Wei-ju Wu Date: Mon, 30 Nov 2015 15:19:37 -0800 Subject: [PATCH] added 30years repository code here --- 30years/README.md | 41 ++++ 30years/iffview/.gitignore | 3 + 30years/iffview/Makefile | 15 ++ 30years/iffview/README.md | 23 +++ 30years/iffview/iffview.c | 208 ++++++++++++++++++++ 30years/iffview/ilbm.c | 220 +++++++++++++++++++++ 30years/iffview/ilbm.h | 80 ++++++++ 30years/intuitoy1/.gitignore | 1 + 30years/intuitoy1/Makefile | 10 + 30years/intuitoy1/README.md | 23 +++ 30years/intuitoy1/intuitoy1.c | 346 ++++++++++++++++++++++++++++++++++ 11 files changed, 970 insertions(+) create mode 100644 30years/README.md create mode 100644 30years/iffview/.gitignore create mode 100644 30years/iffview/Makefile create mode 100644 30years/iffview/README.md create mode 100644 30years/iffview/iffview.c create mode 100644 30years/iffview/ilbm.c create mode 100644 30years/iffview/ilbm.h create mode 100644 30years/intuitoy1/.gitignore create mode 100644 30years/intuitoy1/Makefile create mode 100644 30years/intuitoy1/README.md create mode 100644 30years/intuitoy1/intuitoy1.c diff --git a/30years/README.md b/30years/README.md new file mode 100644 index 0000000..c65c0f4 --- /dev/null +++ b/30years/README.md @@ -0,0 +1,41 @@ +## Description + +To celebrate the 30th anniversary of the Amiga, I decided to write a couple of +small applications that run on classic Amiga computers. The point ? Does there +need to be one ? The Amiga was a fun machine, programming it was fun and +it still is. + +Another goal is to practice Amiga OS development using only free software tools and +libraries (the exception being the OS itself) and gain a deeper understanding +of the system. + +## System Requirements + +The software was developed on a GNU/Linux system with VBCC and GNU make. +It was mostly deployed and tested on FS-UAE. + +I am certain it can be built on different systems, however this will +require modifications. + +## Building + +The software was developed on VBCC and apart from VBCC and NDK, there are no other +dependencies. + +Currently, on a correctly set up development system typing + +``` +make +``` + +should just work. + +### Status + +In progress :) + +## Current applications + + * intuitoy1 - experiments with Intuition (Kickstart 1.x) + * iffview - a simple IFF viewer + diff --git a/30years/iffview/.gitignore b/30years/iffview/.gitignore new file mode 100644 index 0000000..01feec0 --- /dev/null +++ b/30years/iffview/.gitignore @@ -0,0 +1,3 @@ +iffview +ilbm +examples diff --git a/30years/iffview/Makefile b/30years/iffview/Makefile new file mode 100644 index 0000000..0dda7f8 --- /dev/null +++ b/30years/iffview/Makefile @@ -0,0 +1,15 @@ +#CC=vc +aos68k +CC=vc +kick13 +CFLAGS=-c99 -I$(NDK_INC) + +all: iffview + +clean: + rm -f *.o iffview ilbm + +iffview: iffview.o ilbm.o + $(CC) $(CFLAGS) $< -lamiga -lauto -o $@ + +# Mostly for testing +ilbm: ilbm.c + gcc -o $@ $< -DSTANDALONE -DDEBUG diff --git a/30years/iffview/README.md b/30years/iffview/README.md new file mode 100644 index 0000000..972a870 --- /dev/null +++ b/30years/iffview/README.md @@ -0,0 +1,23 @@ +## iffview - A simple IFF viewer application + +### Description + +Writing a simple IFF viewing tool. The learning purpose is to see how to use the +different available display modes and screens on Intuition + +### Building + +Developed with VBCC, on your system type + +``` +make +``` + +### Running + +Open the command line interface on your real Amiga or emulator and type + +``` +iffview +``` + diff --git a/30years/iffview/iffview.c b/30years/iffview/iffview.c new file mode 100644 index 0000000..fb102d2 --- /dev/null +++ b/30years/iffview/iffview.c @@ -0,0 +1,208 @@ +/* iffview.c - IFF ILBM viewer application for Amiga OS >= 1.3 + + This file is part of amiga30yrs. + + amiga30yrs is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + amiga30yrs is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with amiga30yrs. If not, see . + */ +#include + +#include +#include + +#include +#include +#include +#include + +#ifdef __VBCC__ +#include +#endif + +#define WIN_LEFT 10 +#define WIN_TOP 10 +#define WIN_WIDTH 320 +#define WIN_HEIGHT 200 +#define WIN_TITLE "IFF Viewer" +#define WIN_MIN_WIDTH 10 +#define WIN_MIN_HEIGHT 10 +#define WIN_MAX_WIDTH 200 +#define WIN_MAX_HEIGHT 200 + +#define FILE_MENU_NUM 0 +#define NUM_FILE_MENU_ITEMS 2 + +#define OPEN_MENU_ITEM_NUM 0 +#define QUIT_MENU_ITEM_NUM 1 + +struct NewWindow newwin = { + WIN_LEFT, WIN_TOP, WIN_WIDTH, WIN_HEIGHT, 0, 1, + IDCMP_CLOSEWINDOW | IDCMP_MENUPICK, + WINDOWCLOSE | SMART_REFRESH | ACTIVATE | WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH | NOCAREREFRESH, + NULL, NULL, WIN_TITLE, + NULL, NULL, + WIN_MIN_WIDTH, WIN_MIN_HEIGHT, + WIN_MAX_WIDTH, WIN_MAX_HEIGHT, + WBENCHSCREEN +}; + +struct IntuiText menutext[] = { + {0, 1, JAM2, 0, 1, NULL, "Open...", NULL}, + {0, 1, JAM2, 0, 1, NULL, "Quit", NULL} +}; + +struct MenuItem fileMenuItems[] = { + {&fileMenuItems[1], 0, 0, 0, 0, ITEMTEXT | ITEMENABLED | HIGHCOMP | COMMSEQ, 0, + &menutext[0], NULL, 'O', NULL, 0}, + {NULL, 0, 0, 0, 0, ITEMTEXT | ITEMENABLED | HIGHCOMP | COMMSEQ, 0, + &menutext[1], NULL, 'Q', NULL, 0} +}; + +struct Menu menus[] = { + {NULL, 20, 0, 0, 0, MENUENABLED | MIDRAWN, "File", &fileMenuItems[0], 0, 0, 0, 0} +}; + +struct Window *window; + +void cleanup() +{ + if (window) { + ClearMenuStrip(window); + CloseWindow(window); + } +} + + +#define OK_BUTTON_WIDTH 40 +#define OK_BUTTON_HEIGHT 24 +#define REQ_WIDTH 200 +#define REQ_HEIGHT 100 +#define TOPAZ_BASELINE 8 + +void open_file() +{ + struct Requester requester; + struct IntuiText button_text = {1, 0, JAM2, 0, TOPAZ_BASELINE, NULL, "Ok", NULL}; + WORD button_border_points[] = { + 0, 0, OK_BUTTON_WIDTH, 0, OK_BUTTON_WIDTH, OK_BUTTON_HEIGHT, 0, OK_BUTTON_HEIGHT, 0, 0 + }; + struct Border button_border = {0, 0, 1, 0, JAM1, 5, button_border_points, NULL}; + + WORD req_border_points[] = { + 0, 0, REQ_WIDTH, 0, REQ_WIDTH, REQ_HEIGHT, 0, REQ_HEIGHT, 0, 0 + }; + struct Border req_border = {0, 0, 1, 0, JAM1, 5, req_border_points, NULL}; + BOOL result; + + struct Gadget button1 = { + NULL, 10, 10, OK_BUTTON_WIDTH, OK_BUTTON_HEIGHT, + GFLG_GADGHCOMP, 0, GTYP_BOOLGADGET | GTYP_REQGADGET, + &button_border, NULL, &button_text, + 0, NULL, 0, NULL + }; + InitRequester(&requester); + requester.LeftEdge = 20; + requester.TopEdge = 20; + requester.Width = REQ_WIDTH; + requester.Height = REQ_HEIGHT; + requester.Flags = 0; + requester.BackFill = 0; + requester.ReqGadget = &button1; + requester.ReqBorder = &req_border; + result = Request(&requester, window); + if (result) puts("Requester could be opened"); + else puts("Requester could not be opened"); +} + +BOOL handle_menu(UWORD menuNum, UWORD itemNum, UWORD subItemNum) +{ + printf("menu, menu num: %d, item num: %d, sub item num: %d\n", + (int) menuNum, (int) itemNum, (int) subItemNum); + if (menuNum == FILE_MENU_NUM && itemNum == QUIT_MENU_ITEM_NUM) { + /* quit */ + return TRUE; + } + if (menuNum == FILE_MENU_NUM && itemNum == OPEN_MENU_ITEM_NUM) { + open_file(); + } + return FALSE; +} + +void handle_events() { + BOOL done = FALSE; + struct IntuiMessage *msg; + ULONG msgClass; + UWORD menuCode; + + while (!done) { + Wait(1 << window->UserPort->mp_SigBit); + if (msg = (struct IntuiMessage *) GetMsg(window->UserPort)) { + msgClass = msg->Class; + switch (msgClass) { + case IDCMP_CLOSEWINDOW: + done = TRUE; + break; + case IDCMP_MENUPICK: + menuCode = msg->Code; + done = handle_menu(MENUNUM(menuCode), ITEMNUM(menuCode), SUBNUM(menuCode)); + break; + default: + break; + } + ReplyMsg((struct Message *) msg); + } + } +} + +void setup_menu() +{ + UWORD txWidth, txHeight, txBaseline, txSpacing, itemWidth, itemHeight, numItems; + struct RastPort *rp = &window->WScreen->RastPort; + int i; + + txWidth = rp->TxWidth; + txHeight = rp->TxHeight; + txBaseline = rp->TxBaseline; + txSpacing = rp->TxSpacing; + printf("TxWidth: %d, TxHeight: %d, TxBaseline: %d, TxSpacing: %d\n", + (int) txWidth, (int) txHeight, (int) txBaseline, (int) txSpacing); + + /* Set file menu bounds */ + menus[0].Width = TextLength(rp, "File", strlen("File")) + txWidth; + menus[0].Height = txHeight; + + /* Set file menu items bounds */ + /* We actually need to know what the command uses up */ + itemWidth = txWidth * strlen("Open...") + 50; + itemHeight = txHeight + 2; /* 2 pixels adjustment */ + + numItems = sizeof(fileMenuItems) / sizeof(struct MenuItem); + printf("# file items: %d\n", (int) numItems); + for (i = 0; i < numItems; i++) { + fileMenuItems[i].TopEdge = i * itemHeight; + fileMenuItems[i].Height = itemHeight; + fileMenuItems[i].Width = itemWidth; + } + + SetMenuStrip(window, &menus[0]); +} + +int main(int argc, char **argv) +{ + if (window = OpenWindow(&newwin)) { + setup_menu(); + handle_events(); + } + cleanup(); + return 1; +} diff --git a/30years/iffview/ilbm.c b/30years/iffview/ilbm.c new file mode 100644 index 0000000..84d5f3c --- /dev/null +++ b/30years/iffview/ilbm.c @@ -0,0 +1,220 @@ +/* ilbm.c - Universal IFF ILBM handling module + + This file is part of amiga30yrs. + + amiga30yrs is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + amiga30yrs is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with amiga30yrs. If not, see . +*/ +#include +#include +#include + +#include "ilbm.h" + +#ifdef LITTLE_ENDIAN +#include +#endif + +#define IFF_HEADER_SIZE 12 +#define CHUNK_HEADER_SIZE 8 + +BitMapHeader *read_BMHD(FILE *fp, int datasize) +{ + BitMapHeader *header; + int bytes_read; + + header = malloc(sizeof(BitMapHeader)); + bytes_read = fread(header, sizeof(char), datasize, fp); + +#ifdef LITTLE_ENDIAN + header->x = __bswap_16(header->x); + header->y = __bswap_16(header->y); + header->w = __bswap_16(header->w); + header->h = __bswap_16(header->h); + header->transparentColor = __bswap_16(header->transparentColor); + header->pageWidth = __bswap_16(header->pageWidth); + header->pageHeight = __bswap_16(header->pageHeight); +#endif + + /* + printf("x: %d y: %d w: %d h: %d\n", + header.x, header.y, header.w, header.h); + printf("# planes: %d\n", header.nPlanes); + printf("# transp col: %d\n", header.transparentColor); + printf("pagewidth: %d pageheight: %d\n", header.pageWidth, header.pageHeight); + */ + if (header->compression == cmpNone) puts("no compression"); + else if (header->compression == cmpByteRun1) puts("Byte Run 1 compression"); + else puts("unknown compression"); + return header; +} + +ColorRegister *read_CMAP(FILE *fp, int datasize) +{ + int num_colors = datasize / 3, bytes_read; + ColorRegister *colors; + + colors = malloc(datasize); + bytes_read = fread(colors, sizeof(ColorRegister), num_colors, fp); + return colors; +} + +ULONG read_CAMG(FILE *fp, int datasize) +{ + ULONG flags, bytes_read; + bytes_read = fread(&flags, sizeof(ULONG), 1, fp); +#ifdef LITTLE_ENDIAN + flags = __bswap_32(flags); +#endif + if (flags & HAM) puts("HAM mode !"); + else if (flags & EXTRA_HALFBRITE) puts("Extra Halfbrite mode !"); + + return flags; +} + +void read_CRNG(FILE *fp, int datasize) +{ + ULONG bytes_read; + CRange color_reg_range; + bytes_read = fread(&color_reg_range, sizeof(CRange), 1, fp); +#ifdef LITTLE_ENDIAN + color_reg_range.rate = __bswap_16(color_reg_range.rate); + color_reg_range.flags = __bswap_16(color_reg_range.flags); +#endif +#ifdef DEBUG + printf("CRange, rate: %d, flags: %04x, low: %d, high: %d\n", + (int) color_reg_range.rate, (int) color_reg_range.flags, + (int) color_reg_range.low, (int) color_reg_range.high); +#endif +} + +UBYTE *read_BODY(FILE *fp, int datasize, BitMapHeader *bmheader) +{ + ULONG bytes_read; + BYTE *buffer = malloc(datasize), *dst_buffer; + int src_i = 0, dst_i = 0, dst_size; + + dst_size = bmheader->w * bmheader->h * bmheader->nPlanes / 8; + printf("target size: %d, data size: %d\n", dst_size, datasize); + bytes_read = fread(buffer, sizeof(char), datasize, fp); + + if (bmheader->compression == cmpByteRun1) { + BYTE b0, b1; + int i; + /* decompress data */ + dst_buffer = malloc(dst_size); + while (src_i < datasize) { + b0 = buffer[src_i++]; + if (b0 >= 0) { + for (i = 0; i < b0 + 1; i++) dst_buffer[dst_i++] = buffer[src_i++]; + } else { + b1 = buffer[src_i++]; + for (i = 0; i < -b0 + 1; i++) dst_buffer[dst_i++] = b1; + } + } + free(buffer); + return dst_buffer; + } + return buffer; +} + +#define skip_chunk(fp, datasize) fseek(fp, datasize, SEEK_CUR) + +void read_chunks(FILE *fp, int filesize, int total_read) +{ + char id[5], buffer[CHUNK_HEADER_SIZE]; + int i, bytes_read, datasize; + BitMapHeader *bmheader = NULL; + ColorRegister *colors = NULL; + UBYTE *imgdata = NULL; + + while (total_read < filesize) { + + bytes_read = fread(buffer, sizeof(char), 8, fp); + + for (i = 0; i < 4; i++) id[i] = buffer[i]; + id[4] = 0; + +#ifdef LITTLE_ENDIAN + datasize = __bswap_32(*((ULONG *) &buffer[4])); +#else + datasize = *((ULONG *) &buffer[4]); +#endif + + if (!strncmp("BMHD", buffer, 4)) bmheader = read_BMHD(fp, datasize); + else if (!strncmp("CMAP", buffer, 4)) colors = read_CMAP(fp, datasize); + else if (!strncmp("CRNG", buffer, 4)) read_CRNG(fp, datasize); + else if (!strncmp("CAMG", buffer, 4)) read_CAMG(fp, datasize); + else if (!strncmp("BODY", buffer, 4)) imgdata = read_BODY(fp, datasize, bmheader); + else { +#ifdef DEBUG + printf("WARNING - Unsupported chunk '%s', size: %d\n", id, datasize); +#endif + skip_chunk(fp, datasize); + } + /* Padding to even if necessary */ + if (datasize % 2) { + fseek(fp, 1, SEEK_CUR); + datasize++; + } + total_read += datasize + CHUNK_HEADER_SIZE; + } + if (imgdata) free(imgdata); + if (colors) free(colors); + if (bmheader) free(bmheader); +} + +void parse_file(const char *path) +{ + FILE *fp; + char buffer[IFF_HEADER_SIZE]; + size_t bytes_read; + ULONG filesize, total_read = 0; + + fp = fopen(path, "rb"); + + /* need to check whether we actually can read this much*/ + bytes_read = fread(buffer, sizeof(char), IFF_HEADER_SIZE, fp); + total_read += bytes_read; + + if (!strncmp("FORM", buffer, 4)) { + +#ifdef LITTLE_ENDIAN + filesize = __bswap_32(*((ULONG *) &buffer[4])) + CHUNK_HEADER_SIZE; +#else + filesize = *((ULONG *) &buffer[4]) + CHUNK_HEADER_SIZE; +#endif + + if (!strncmp("ILBM", &buffer[8], 4)) { +#ifdef DEBUG + printf("IFF/ILBM file, file size: %d\n", (int) filesize); +#endif + read_chunks(fp, filesize, total_read); + } else { + puts("not an IFF ILBM file"); + } + } else { + puts("not an IFF file"); + } +} + +#ifdef STANDALONE +int main(int argc, char **argv) +{ + if (argc <= 1) { + puts("usage: ilbm "); + } else { + parse_file(argv[1]); + } +} +#endif diff --git a/30years/iffview/ilbm.h b/30years/iffview/ilbm.h new file mode 100644 index 0000000..a469a8d --- /dev/null +++ b/30years/iffview/ilbm.h @@ -0,0 +1,80 @@ +/* ilbm.h - Definitions for IFF ILBM handling module + + This file is part of amiga30yrs. + + amiga30yrs is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + amiga30yrs is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with amiga30yrs. If not, see . + */ +#pragma once +#ifndef __ILBM_H__ +#define __ILBM_H__ + +#ifdef __VBCC__ + +#include +#include + +#else + +#include +#define ULONG u_int32_t +#define UWORD u_int16_t +#define UBYTE u_int8_t + +#define LONG int32_t +#define WORD int16_t +#define BYTE int8_t + +#define HAM 0x800 +#define EXTRA_HALFBRITE 0x80 + +#endif + +/* + * From the specification + */ +typedef UBYTE Masking; /* Choice of masking technique. */ + +#define mskNone 0 +#define mskHasMask 1 +#define mskHasTransparentColor 2 +#define mskLasso 3 + +typedef UBYTE Compression; +#define cmpNone 0 +#define cmpByteRun1 1 + +typedef struct { + UWORD w, h; + WORD x, y; + UBYTE nPlanes; + Masking masking; + Compression compression; + UBYTE pad1; + UWORD transparentColor; + UBYTE xAspect, yAspect; + WORD pageWidth, pageHeight; +} BitMapHeader; + +typedef struct { + UBYTE red, green, blue; +} ColorRegister; + +typedef struct { + WORD pad1; + WORD rate; + WORD flags; + UBYTE low, high; +} CRange; + +#endif /* __ILBM_H__ */ diff --git a/30years/intuitoy1/.gitignore b/30years/intuitoy1/.gitignore new file mode 100644 index 0000000..4ebf588 --- /dev/null +++ b/30years/intuitoy1/.gitignore @@ -0,0 +1 @@ +intuitoy1 diff --git a/30years/intuitoy1/Makefile b/30years/intuitoy1/Makefile new file mode 100644 index 0000000..1d6a11c --- /dev/null +++ b/30years/intuitoy1/Makefile @@ -0,0 +1,10 @@ +CC=vc +kick13 +CFLAGS=-c99 -I$(NDK_INC) + +all: intuitoy1 + +clean: + rm -f *.o intuitoy1 + +intuitoy1: intuitoy1.c + $(CC) $(CFLAGS) $^ -lamiga -lauto -o $@ diff --git a/30years/intuitoy1/README.md b/30years/intuitoy1/README.md new file mode 100644 index 0000000..9985862 --- /dev/null +++ b/30years/intuitoy1/README.md @@ -0,0 +1,23 @@ +## intuitoy1 - Experiments with Intuition on Amiga OS 1.x + +### Description + +Trying out to create the available elements that Intuition provides to use them effectively +in an application. Besides being a learning tool for Amiga 1.x UI programming, it is completely +and utterly useless. + +### Building + +``` +make +``` + +### Running + +On an Amiga system (emulator or real), open the command line interface and +enter + +``` +intuitoy1 +``` + diff --git a/30years/intuitoy1/intuitoy1.c b/30years/intuitoy1/intuitoy1.c new file mode 100644 index 0000000..b9ecee1 --- /dev/null +++ b/30years/intuitoy1/intuitoy1.c @@ -0,0 +1,346 @@ +/* intuitoy1.c - Intuition experiments for Amiga OS 1.x + + This file is part of amiga30yrs. + + amiga30yrs is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + amiga30yrs is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with amiga30yrs. If not, see . + */ +#include + +#include +#include + +#include +#include +#include +#include + +#ifdef __VBCC__ +#include +#endif + +#define WIN_LEFT 10 +#define WIN_TOP 10 +#define WIN_WIDTH 320 +#define WIN_HEIGHT 200 +#define WIN_TITLE "IntuiToy 1" +#define WIN_MIN_WIDTH 10 +#define WIN_MIN_HEIGHT 10 +#define WIN_MAX_WIDTH 200 +#define WIN_MAX_HEIGHT 200 + +#define BUTTON_HEIGHT 20 +#define BUTTON_TEXT_XOFFSET 4 +#define TOPAZ_BASELINE 6 + +#define FILE_MENU_NUM 0 +#define NUM_FILE_MENU_ITEMS 2 + +#define OPEN_MENU_ITEM_NUM 0 +#define QUIT_MENU_ITEM_NUM 1 + +struct NewWindow newwin = { + WIN_LEFT, WIN_TOP, WIN_WIDTH, WIN_HEIGHT, 0, 1, + IDCMP_CLOSEWINDOW | IDCMP_MENUPICK | IDCMP_GADGETUP, + WINDOWCLOSE | SMART_REFRESH | ACTIVATE | WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH | NOCAREREFRESH, + NULL, NULL, WIN_TITLE, + NULL, NULL, + WIN_MIN_WIDTH, WIN_MIN_HEIGHT, + WIN_MAX_WIDTH, WIN_MAX_HEIGHT, + WBENCHSCREEN +}; + +struct IntuiText menutext[] = { + {0, 1, JAM2, 0, 1, NULL, "Open...", NULL}, + {0, 1, JAM2, 0, 1, NULL, "Quit", NULL} +}; + +struct MenuItem fileMenuItems[] = { + {&fileMenuItems[1], 0, 0, 0, 0, ITEMTEXT | ITEMENABLED | HIGHCOMP | COMMSEQ, 0, + &menutext[0], NULL, 'O', NULL, 0}, + {NULL, 0, 0, 0, 0, ITEMTEXT | ITEMENABLED | HIGHCOMP | COMMSEQ, 0, + &menutext[1], NULL, 'Q', NULL, 0} +}; + +struct Menu menus[] = { + {NULL, 20, 0, 0, 0, MENUENABLED | MIDRAWN, "File", &fileMenuItems[0], 0, 0, 0, 0} +}; + +struct Window *window; + +void cleanup() +{ + if (window) { + ClearMenuStrip(window); + CloseWindow(window); + } +} + +#define REQ_WIDTH 180 +#define REQ_HEIGHT 70 +#define REQ_TEXT_XOFFSET 10 + +#define OK_BUTTON_X 10 +#define OK_BUTTON_Y 40 +#define OK_BUTTON_WIDTH 24 + +#define CANCEL_BUTTON_X 120 +#define CANCEL_BUTTON_Y 40 +#define CANCEL_BUTTON_WIDTH 54 + +#define PATH_GADGET_WIDTH 160 + + +/* + * This opens a very rudimentary file dialog, that demonstrates a true requester, which + * is dependent on the parent window. + */ +void open_file() +{ + /* Note that all data here is static. + The reason is that Intuition expects the data to still exist for the lifetime of the + requester. If it's gone, the Guru will greet you. + */ + static struct Requester requester; + static WORD req_border_points[] = { + 0, 0, REQ_WIDTH - 1, 0, REQ_WIDTH - 1, REQ_HEIGHT - 1, 0, REQ_HEIGHT - 1, 0, 0 + }; + static struct Border req_border = {0, 0, 1, 0, JAM1, 5, req_border_points, NULL}; + + static struct IntuiText labels[] = { + {1, 0, JAM2, REQ_TEXT_XOFFSET, TOPAZ_BASELINE, NULL, "Enter file path", NULL}, + {1, 0, JAM2, BUTTON_TEXT_XOFFSET, TOPAZ_BASELINE, NULL, "Ok", NULL}, + {1, 0, JAM2, BUTTON_TEXT_XOFFSET, TOPAZ_BASELINE, NULL, "Cancel", NULL} + }; + static WORD gadget_border_points[3][10] = { + {0, 0, OK_BUTTON_WIDTH, 0, OK_BUTTON_WIDTH, BUTTON_HEIGHT, 0, BUTTON_HEIGHT, 0, 0}, + {0, 0, CANCEL_BUTTON_WIDTH, 0, CANCEL_BUTTON_WIDTH, BUTTON_HEIGHT, 0, BUTTON_HEIGHT, 0, 0}, + {-2, -2, PATH_GADGET_WIDTH, -2, PATH_GADGET_WIDTH, 10, -2, 10, -2, -2} + }; + static struct Border gadget_borders[] = { + {0, 0, 1, 0, JAM1, 5, gadget_border_points[0], NULL}, + {0, 0, 1, 0, JAM1, 5, gadget_border_points[1], NULL}, + {0, 0, 1, 0, JAM1, 5, gadget_border_points[2], NULL} + }; + static UBYTE buffer[81], undobuffer[81]; + static struct StringInfo strinfo = {buffer, undobuffer, 0, 80, 0, 0, 0, 0, 0, 0, NULL, 0, NULL}; + + static struct Gadget gadgets[] = { + {&gadgets[1], OK_BUTTON_X, OK_BUTTON_Y, OK_BUTTON_WIDTH, BUTTON_HEIGHT, GFLG_GADGHCOMP, + GACT_RELVERIFY | GACT_ENDGADGET, GTYP_BOOLGADGET | GTYP_REQGADGET, + &gadget_borders[0], NULL, &labels[1], 0, NULL, 101, NULL}, + {&gadgets[2], CANCEL_BUTTON_X, CANCEL_BUTTON_Y, CANCEL_BUTTON_WIDTH, BUTTON_HEIGHT, GFLG_GADGHCOMP, + GACT_RELVERIFY | GACT_ENDGADGET, GTYP_BOOLGADGET | GTYP_REQGADGET, + &gadget_borders[1], NULL, &labels[2], 0, NULL, 102, NULL}, + {NULL, OK_BUTTON_X, 20, PATH_GADGET_WIDTH, 10, + GFLG_GADGHCOMP, GACT_RELVERIFY, GTYP_STRGADGET, &gadget_borders[2], NULL, &labels[3], + 0, &strinfo, 103, NULL}, + }; + + BOOL result; + InitRequester(&requester); + requester.LeftEdge = 50; + requester.TopEdge = 50; + requester.Width = REQ_WIDTH; + requester.Height = REQ_HEIGHT; + requester.Flags = 0; + requester.BackFill = 0; + requester.ReqGadget = &gadgets[0]; + requester.ReqBorder = &req_border; + requester.ReqText = &labels[0]; + result = Request(&requester, window); + if (result) puts("Requester could be opened"); + else puts("Requester could not be opened"); +} + +BOOL handle_menu(UWORD menuNum, UWORD itemNum, UWORD subItemNum) +{ + printf("menu, menu num: %d, item num: %d, sub item num: %d\n", + (int) menuNum, (int) itemNum, (int) subItemNum); + if (menuNum == FILE_MENU_NUM && itemNum == QUIT_MENU_ITEM_NUM) { + /* quit */ + return TRUE; + } + if (menuNum == FILE_MENU_NUM && itemNum == OPEN_MENU_ITEM_NUM) { + open_file(); + } + return FALSE; +} + +/* + * The main event loop. + */ +void handle_events() { + BOOL done = FALSE; + struct IntuiMessage *msg; + ULONG msgClass; + UWORD menuCode; + + while (!done) { + Wait(1 << window->UserPort->mp_SigBit); + if (msg = (struct IntuiMessage *) GetMsg(window->UserPort)) { + msgClass = msg->Class; + switch (msgClass) { + case IDCMP_CLOSEWINDOW: + done = TRUE; + break; + case IDCMP_MENUPICK: + menuCode = msg->Code; + done = handle_menu(MENUNUM(menuCode), ITEMNUM(menuCode), SUBNUM(menuCode)); + break; + case IDCMP_GADGETUP: + printf("Click me clicked, id: %d\n", (int) ((struct Gadget *) (msg->IAddress))->GadgetID); + break; + default: + break; + } + ReplyMsg((struct Message *) msg); + } + } +} + +/* + * Laying out the pulldown menu strip. + * The menu is also the invocation point to test out requester types. + */ +void setup_menu() +{ + UWORD txWidth, txHeight, txBaseline, txSpacing, itemWidth, itemHeight, numItems; + struct RastPort *rp = &window->WScreen->RastPort; + int i; + + txWidth = rp->TxWidth; + txHeight = rp->TxHeight; + txBaseline = rp->TxBaseline; + txSpacing = rp->TxSpacing; + printf("TxWidth: %d, TxHeight: %d, TxBaseline: %d, TxSpacing: %d\n", + (int) txWidth, (int) txHeight, (int) txBaseline, (int) txSpacing); + + /* Set file menu bounds */ + menus[0].Width = TextLength(rp, "File", strlen("File")) + txWidth; + menus[0].Height = txHeight; + + /* Set file menu items bounds */ + /* We actually need to know what the command uses up */ + itemWidth = txWidth * strlen("Open...") + 50; + itemHeight = txHeight + 2; /* 2 pixels adjustment */ + + numItems = sizeof(fileMenuItems) / sizeof(struct MenuItem); + printf("# file items: %d\n", (int) numItems); + for (i = 0; i < numItems; i++) { + fileMenuItems[i].TopEdge = i * itemHeight; + fileMenuItems[i].Height = itemHeight; + fileMenuItems[i].Width = itemWidth; + } + + SetMenuStrip(window, &menus[0]); +} + +/* + * Create some application gadgets inside the window here. Playing around with + * settings, events and layout. + */ +#define CLICKME_BUTTON_WIDTH 90 +#define CLICKME_BUTTON_X 10 +#define CLICKME_BUTTON_Y 20 + +#define CLICKME2_BUTTON_WIDTH 120 +#define CLICKME2_BUTTON_X 110 +#define CLICKME2_BUTTON_Y 20 + +#define SLIDER_WIDTH 200 +#define SLIDER_HEIGHT 10 +#define SLIDER_LABEL_YOFFSET -10 +#define SLIDER_X 10 +#define SLIDER_Y 65 + +#define STRING_X 12 +#define STRING_Y 94 +#define STRING_WIDTH 80 +#define STRING_HEIGHT 10 +#define STRING_LABEL_YOFFSET -14 +#define STRING_BORDER_X -2 +#define STRING_BORDER_Y -2 + +#define INTEGER_X 12 +#define INTEGER_Y 124 +#define INTEGER_WIDTH 80 +#define INTEGER_HEIGHT 10 + +struct Gadget *setup_gadgets() +{ + static struct IntuiText gadget_labels[] = { + {1, 0, JAM2, BUTTON_TEXT_XOFFSET, TOPAZ_BASELINE, NULL, "Click me !", NULL}, + {1, 0, JAM2, BUTTON_TEXT_XOFFSET, TOPAZ_BASELINE, NULL, "Click me too !", NULL}, + {1, 0, JAM2, BUTTON_TEXT_XOFFSET, SLIDER_LABEL_YOFFSET, NULL, "A slider", NULL}, + {1, 0, JAM2, BUTTON_TEXT_XOFFSET, STRING_LABEL_YOFFSET, NULL, "A string gadget", NULL}, + {1, 0, JAM2, BUTTON_TEXT_XOFFSET, STRING_LABEL_YOFFSET, NULL, "An integer gadget", NULL} + }; + static WORD gadget_border_points[3][10] = { + {0, 0, CLICKME_BUTTON_WIDTH, 0, CLICKME_BUTTON_WIDTH, BUTTON_HEIGHT, + 0, BUTTON_HEIGHT, 0, 0}, + {0, 0, CLICKME2_BUTTON_WIDTH, 0, CLICKME2_BUTTON_WIDTH, BUTTON_HEIGHT, + 0, BUTTON_HEIGHT, 0, 0}, + {STRING_BORDER_X, STRING_BORDER_Y, STRING_WIDTH, STRING_BORDER_Y, + STRING_WIDTH, STRING_HEIGHT, STRING_BORDER_X, STRING_HEIGHT, + STRING_BORDER_X, STRING_BORDER_Y} + }; + static struct Border gadget_border[] = { + {0, 0, 1, 0, JAM1, 5, gadget_border_points[0], NULL}, + {0, 0, 1, 0, JAM1, 5, gadget_border_points[1], NULL}, + {0, 0, 1, 0, JAM1, 5, gadget_border_points[2], NULL} + }; + static struct PropInfo propinfos[] = { + {AUTOKNOB | FREEHORIZ, 0, 0, 10, MAXBODY, 0, 0, 0, 0, 0, 0} + }; + static struct Image slider_image; + static UBYTE buffer[11], undobuffer[11], buffer2[11], undobuffer2[11]; + static struct StringInfo strinfos[] = { + {buffer, undobuffer, 0, 10, 0, 0, 0, 0, 0, 0, NULL, 0, NULL}, + {buffer2, undobuffer2, 0, 10, 0, 0, 0, 0, 0, 0, NULL, 0, NULL} + }; + static struct Gadget gadgets[] = { + {&gadgets[1], CLICKME_BUTTON_X, CLICKME_BUTTON_Y, CLICKME_BUTTON_WIDTH, BUTTON_HEIGHT, + GFLG_GADGHBOX, GACT_RELVERIFY, GTYP_BOOLGADGET, &gadget_border[0], NULL, &gadget_labels[0], + 0, NULL, 1, NULL}, + {&gadgets[2], CLICKME2_BUTTON_X, CLICKME2_BUTTON_Y, CLICKME2_BUTTON_WIDTH, BUTTON_HEIGHT, + GFLG_GADGHCOMP, GACT_RELVERIFY, GTYP_BOOLGADGET, &gadget_border[1], NULL, &gadget_labels[1], + 0, NULL, 2, NULL}, + {&gadgets[3], SLIDER_X, SLIDER_Y, SLIDER_WIDTH, SLIDER_HEIGHT, + GFLG_GADGHCOMP, GACT_RELVERIFY, GTYP_PROPGADGET, &slider_image, NULL, &gadget_labels[2], + 0, &propinfos[0], 3, NULL}, + {&gadgets[4], STRING_X, STRING_Y, STRING_WIDTH, STRING_HEIGHT, + GFLG_GADGHCOMP, GACT_RELVERIFY, GTYP_STRGADGET, &gadget_border[2], NULL, &gadget_labels[3], + 0, &strinfos[0], 3, NULL}, + {NULL, INTEGER_X, INTEGER_Y, INTEGER_WIDTH, INTEGER_HEIGHT, + GFLG_GADGHCOMP, GACT_LONGINT, GTYP_STRGADGET, &gadget_border[2], NULL, &gadget_labels[4], + 0, &strinfos[1], 3, NULL}, + }; + buffer[0] = 0; + undobuffer[0] = 0; + buffer2[0] = 0; + undobuffer2[0] = 0; + strcpy(buffer2, "0"); + return &gadgets[0]; +} + +int main(int argc, char **argv) +{ + newwin.FirstGadget = setup_gadgets(); + if (window = OpenWindow(&newwin)) { + setup_menu(); + handle_events(); + } + cleanup(); + return 1; +}