From 7746095dd739d2de82035c92c129bb2a37a7ad34 Mon Sep 17 00:00:00 2001 From: Wei-ju Wu Date: Sun, 17 Jan 2016 22:08:58 -0800 Subject: [PATCH] requesters update - scanning directory now adds the path parameter - file requester now sizes the requester according to the file list and window font --- README.md | 20 ++++--- requesters/dos13.c | 2 +- requesters/dos13.h | 5 +- requesters/filereq.c | 139 +++++++++++++++++++++++++++++++------------ 4 files changed, 117 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 5681c6b..99b7aa5 100644 --- a/README.md +++ b/README.md @@ -3,19 +3,21 @@ ## Description A random collection of my Amiga related programs, mostly written for AmigaOS -on classic Motorola 68k hardware. +on classic Motorola 68k hardware. This is for the purpose of learning +and sharing with other programmers in the Amiga community, so we can +spread an improve the understanding in order to write better software +for our platforms. -Since I have 9 Amiga computers of various models (1000, 500, 1200, 4000) -spread around my house, I figured I should put them to good use. It also -has the nice side-effect that I learn to develop for AROS, AmigaOS 4.x and -MorphOS as well. +Since I have number of classic Amiga, AmigaOS 4, MorphOS and AROS machines spread +around my house, I figured I should put them to good use, deepen my understanding +of these systems and improve my C and general programming skills. -Most code was developed with the VBCC compiler on a GNU/Linux system, -but I might add builds for GCC and SAS/C when it makes sense. +The C code was developed with the VBCC and gcc compilers on a GNU/Linux system using +the C99 setting. I think that cross-compiling is the most effective way to program the Amiga - commodity systems for development, vintage custom systems for deployment. -Might contain scripts in Python, Racket or Scala for certain tools, since -these are my current tools of choice. \ No newline at end of file +There are also scripts in Python, Racket or Scala for certain tools that prepare +and process data. diff --git a/requesters/dos13.c b/requesters/dos13.c index b8a3d4e..042d464 100644 --- a/requesters/dos13.c +++ b/requesters/dos13.c @@ -26,7 +26,7 @@ extern struct Library *DOSBase; For now, we will omit device typed entries, because writing/reading to them usually doesn't make too much sense. */ -struct FileListEntry *scan_current_dir() +struct FileListEntry *scan_dir(const char *dirpath) { struct DosLibrary *dosbase = (struct DosLibrary *) DOSBase; Forbid(); diff --git a/requesters/dos13.h b/requesters/dos13.h index 2e7d3ad..9a8d7de 100644 --- a/requesters/dos13.h +++ b/requesters/dos13.h @@ -23,9 +23,10 @@ struct FileListEntry { }; /* - * scan the current directory + * Scans the specified directory and returns the entries, if dirpath is NULL, + * returns the list of all logical volumes. */ -extern struct FileListEntry *scan_current_dir(); +extern struct FileListEntry *scan_dir(const char *dirpath); /* free the resources allocated in the specified entry list */ void free_file_list(struct FileListEntry *entries); diff --git a/requesters/filereq.c b/requesters/filereq.c index d05b5c2..39a959d 100644 --- a/requesters/filereq.c +++ b/requesters/filereq.c @@ -11,6 +11,10 @@ #include "filereq.h" #include "dos13.h" +#define BUTTON_HMARGIN 5 +#define REQ_HMARGIN 10 +#define REQ_VMARGIN 14 + #define LABEL_DRAWER 0 #define LABEL_FILE 1 #define LABEL_PARENT 2 @@ -18,10 +22,7 @@ #define LABEL_OPEN 4 #define LABEL_CANCEL 5 -#define REQWIN_WIDTH 260 #define REQWIN_HEIGHT 180 -#define REQ_X 10 -#define REQ_Y 16 #define REQ_WIDTH 240 #define REQ_HEIGHT 175 #define TOPAZ_BASELINE 8 @@ -52,22 +53,22 @@ #define FILE_LIST_X 0 #define FILE_LIST_Y 0 -#define FILE_LIST_WIDTH 229 +//#define FILE_LIST_WIDTH 229 + +static int filelist_width; +static int filelist_bm_width; + #define FILE_LIST_HEIGHT 86 #define FILE_LIST_BM_X 1 #define FILE_LIST_BM_Y 1 -#define FILE_LIST_BM_WIDTH (FILE_LIST_WIDTH - 2) #define FILE_LIST_BM_HEIGHT (FILE_LIST_HEIGHT - 2) -#define LIST_VSLIDER_X FILE_LIST_WIDTH #define LIST_VSLIDER_Y 0 #define LIST_VSLIDER_WIDTH 11 #define LIST_VSLIDER_HEIGHT 65 -#define LIST_UP_X FILE_LIST_WIDTH #define LIST_UP_Y 65 -#define LIST_DOWN_X LIST_UP_X #define LIST_DOWN_Y (LIST_UP_Y + LIST_BUTTON_HEIGHT) #define LIST_BUTTON_WIDTH 11 #define LIST_BUTTON_HEIGHT 11 @@ -113,8 +114,7 @@ static WORD drives_border_points[] = {0, 0, DRIVES_BUTTON_WIDTH, 0, DRIVES_BUTTO static WORD cancel_border_points[] = {0, 0, CANCEL_BUTTON_WIDTH, 0, CANCEL_BUTTON_WIDTH, BUTTON_HEIGHT, 0, BUTTON_HEIGHT, 0, 0}; -static WORD list_border_points[] = {0, 0, FILE_LIST_WIDTH, 0, FILE_LIST_WIDTH, - FILE_LIST_HEIGHT, 0, FILE_LIST_HEIGHT, 0, 0}; +static WORD list_border_points[] = {0, 0, 0, 0, 0, FILE_LIST_HEIGHT, 0, FILE_LIST_HEIGHT, 0, 0}; /* the -2 is the margin to set to avoid that the string gadget will overdraw the borders */ @@ -141,17 +141,17 @@ static struct PropInfo propinfo = {AUTOKNOB | FREEVERT, 0, 0, MAXBODY, MAXBODY, #define WIN_TITLE "Open File..." static struct NewWindow newwin = { - 0, 0, REQWIN_WIDTH, REQWIN_HEIGHT, 0, 1, - IDCMP_GADGETUP, + 0, 0, 0, REQWIN_HEIGHT, 0, 1, + IDCMP_GADGETUP | IDCMP_MOUSEBUTTONS, WFLG_CLOSEGADGET | WFLG_SMART_REFRESH | WFLG_ACTIVATE | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_NOCAREREFRESH, NULL, NULL, WIN_TITLE, NULL, NULL, - REQWIN_WIDTH, REQWIN_HEIGHT, - REQWIN_WIDTH, REQWIN_HEIGHT, + 0, REQWIN_HEIGHT, + 0, REQWIN_HEIGHT, WBENCHSCREEN }; -static struct Gadget list_down = {NULL, LIST_DOWN_X, LIST_DOWN_Y, +static struct Gadget list_down = {NULL, 0, LIST_DOWN_Y, LIST_BUTTON_WIDTH, LIST_BUTTON_HEIGHT, GFLG_GADGHCOMP | GFLG_GADGIMAGE, GACT_RELVERIFY, GTYP_BOOLGADGET | GTYP_REQGADGET, @@ -159,7 +159,7 @@ static struct Gadget list_down = {NULL, LIST_DOWN_X, LIST_DOWN_Y, NULL, 0, NULL, REQ_DOWN_ID, NULL}; -static struct Gadget list_up = {&list_down, LIST_UP_X, LIST_UP_Y, +static struct Gadget list_up = {&list_down, 0, LIST_UP_Y, LIST_BUTTON_WIDTH, LIST_BUTTON_HEIGHT, GFLG_GADGHCOMP | GFLG_GADGIMAGE, GACT_RELVERIFY, GTYP_BOOLGADGET | GTYP_REQGADGET, @@ -167,7 +167,7 @@ static struct Gadget list_up = {&list_down, LIST_UP_X, LIST_UP_Y, NULL, 0, NULL, REQ_UP_ID, NULL}; -static struct Gadget list_vslider = {&list_up, LIST_VSLIDER_X, LIST_VSLIDER_Y, +static struct Gadget list_vslider = {&list_up, 0, LIST_VSLIDER_Y, LIST_VSLIDER_WIDTH, LIST_VSLIDER_HEIGHT, GFLG_GADGHCOMP, GACT_RELVERIFY, GTYP_PROPGADGET, &slider_image, NULL, NULL, 0, &propinfo, @@ -194,7 +194,7 @@ static struct Gadget cancel_button = {&dir_text, CANCEL_BUTTON_X, BUTTON_Y, CANC static struct Gadget parent_button = {&cancel_button, PARENT_BUTTON_X, BUTTON_Y, PARENT_BUTTON_WIDTH, BUTTON_HEIGHT, - GFLG_GADGHCOMP, GACT_RELVERIFY, + GFLG_GADGHCOMP | GFLG_DISABLED, GACT_RELVERIFY, GTYP_BOOLGADGET | GTYP_REQGADGET, &parent_button_border, NULL, &labels[LABEL_PARENT], 0, NULL, @@ -245,6 +245,19 @@ static void close_requester() } } +int file_index(int mx, int my) { + int x1 = REQ_HMARGIN + FILE_LIST_X; + int y1 = REQ_VMARGIN + FILE_LIST_Y; + int x2 = x1 + filelist_width; + int y2 = y1 + FILE_LIST_HEIGHT; + if (mx >= x1 && mx <= x2 && my >= y1 && my <= y2) { + int rely = my - y1; + printf("rely: %d\n", rely); + return 0; + } + return -1; +} + static void handle_events() { BOOL done = FALSE; @@ -258,6 +271,15 @@ static void handle_events() if (msg = (struct IntuiMessage *) GetMsg(req_window->UserPort)) { msgClass = msg->Class; switch (msgClass) { + case IDCMP_MOUSEBUTTONS: + if (msg->Code == SELECTUP) { + WORD mx = msg->MouseX, my = msg->MouseY, file_i = file_index(mx, my); + if (file_i >= 0) { + // TODO + } + } + ReplyMsg((struct Message *) msg); + break; case IDCMP_GADGETUP: buttonId = (int) ((struct Gadget *) (msg->IAddress))->GadgetID; ReplyMsg((struct Message *) msg); @@ -281,7 +303,7 @@ static void cleanup() { for (int i = 0; i < filelist_bm_depth; i++) { if (filelist_bitmap.Planes[i]) FreeRaster(filelist_bitmap.Planes[i], - FILE_LIST_WIDTH, + filelist_width, FILE_LIST_HEIGHT); } } @@ -289,7 +311,7 @@ static void cleanup() void draw_list() { - struct FileListEntry *files = scan_current_dir(), *cur; + struct FileListEntry *files = scan_dir(NULL), *cur; // Note that we need to render into the requester // layer's rastport, because it is rendered on top of the @@ -310,42 +332,85 @@ void draw_list() ypos += font_height; if (ypos > FILE_LIST_BM_HEIGHT) break; } - BltBitMapRastPort(&filelist_bitmap, 0, 0, dst_rp, - FILE_LIST_BM_X, FILE_LIST_BM_Y, FILE_LIST_BM_WIDTH, FILE_LIST_BM_HEIGHT, - 0xc0); + SetDrMd(src_rp, COMPLEMENT); + // Draw selection rectangle + RectFill(src_rp, 8, 12, filelist_bm_width - 8, 18); free_file_list(files); + + // Done drawing, offscreen bitmap is rendered, copy to the requester's layer + ClipBlit(src_rp, 0, 0, dst_rp, + FILE_LIST_BM_X, FILE_LIST_BM_Y, filelist_bm_width, FILE_LIST_BM_HEIGHT, + 0xc0); +} + +// Initialize the requester window and gadget sizes +// according to the current font and screen resolutions +void init_sizes(struct Window *window, struct Requester *requester) +{ + int scrw = window->WScreen->Width; + int scrh = window->WScreen->Height; + // Determine the width of the requester. This is + // the maximum of the width of the button bar and + // the file list. + // The width of the file list is the width to hold 30 characters + // in the current font + filelist_width = TextLength(window->RPort, "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW", 30) + 10; + filelist_bm_width = filelist_width - 2; + + int buttonbar_width = TextLength(window->RPort, "OpenDrivesParentCancel", 22) + + (BUTTON_HMARGIN * 2 * 4); + int req_width = filelist_width > buttonbar_width ? filelist_width : buttonbar_width; + printf("filelist width: %d, button bar width: %d, req_width: %d\n", filelist_width, + buttonbar_width, req_width); + req_width += LIST_VSLIDER_WIDTH; + + newwin.MinWidth = newwin.MaxWidth = newwin.Width = req_width + 2 * REQ_HMARGIN; + // TODO: respect screen size + newwin.LeftEdge = window->LeftEdge + 10; + newwin.TopEdge = window->TopEdge + 10; + + // adjust border + list_border_points[2] = filelist_width; + list_border_points[4] = filelist_width; + // adjust gadgets + list_down.LeftEdge = filelist_width; + list_up.LeftEdge = filelist_width; + list_vslider.LeftEdge = filelist_width; + + requester->Width = req_width; + requester->LeftEdge = REQ_HMARGIN; + requester->TopEdge = REQ_VMARGIN; + requester->Height = REQ_HEIGHT; + requester->Flags = SIMPLEREQ | NOREQBACKFILL | NOISYREQ; + requester->BackFill = 0; + requester->ReqGadget = &ok_button; + requester->ReqBorder = &file_list_border; + requester->ReqText = NULL; } void open_file(struct Window *window) { BOOL result; + InitRequester(&requester); + init_sizes(window, &requester); if (req_window = OpenWindow(&newwin)) { - InitRequester(&requester); - requester.LeftEdge = REQ_X; - requester.TopEdge = REQ_Y; - requester.Width = REQ_WIDTH; - requester.Height = REQ_HEIGHT; - requester.Flags = SIMPLEREQ | NOREQBACKFILL; - requester.BackFill = 0; - requester.ReqGadget = &ok_button; - requester.ReqBorder = &file_list_border; - requester.ReqText = NULL; - reqwin_font = req_window->IFont; font_height = reqwin_font->tf_YSize; font_baseline = reqwin_font->tf_Baseline; printf("Font ysize: %d, baseline: %d\n", (int) font_height, (int) font_baseline); - InitBitMap(&filelist_bitmap, filelist_bm_depth, FILE_LIST_BM_WIDTH, FILE_LIST_BM_HEIGHT); + // TODO: the offline bitmap should be higher by one text line than the + // visible area, since clipping doesn't work easily on drawing text + InitBitMap(&filelist_bitmap, filelist_bm_depth, filelist_bm_width, FILE_LIST_BM_HEIGHT); for (int i = 0; i < filelist_bm_depth; i++) filelist_bitmap.Planes[i] = NULL; for (int i = 0; i < filelist_bm_depth; i++) { - if (!(filelist_bitmap.Planes[i] = AllocRaster(FILE_LIST_WIDTH, FILE_LIST_HEIGHT))) { + if (!(filelist_bitmap.Planes[i] = AllocRaster(filelist_width, FILE_LIST_HEIGHT))) { cleanup(); return; } else { BltClear(filelist_bitmap.Planes[i], - RASSIZE(FILE_LIST_WIDTH, FILE_LIST_HEIGHT), 1); + RASSIZE(filelist_width, FILE_LIST_HEIGHT), 1); } } InitRastPort(&filelist_rastport);