ToolsMenu/gui.c

619 行
16 KiB
C
実行ファイル

/*
ToolsMenu - Add tools to the Workbench Tools menu
Copyright (C) 2015, 2018 Kim Fastrup Larsen
This program 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 ver-
sion 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be use-
ful, but WITHOUT ANY WARRANTY; without even the implied war-
ranty 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 Li-
cense along with this program. If not, see
<http://www.gnu.org/licenses/>.
The author can be contacted on <kimflarsen@hotmail.com>
*/
#define INTUI_V36_NAMES_ONLY
#include <dos/dos.h>
#include <exec/memory.h>
#include <exec/ports.h>
#include <intuition/gadgetclass.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <libraries/gadtools.h>
#include <clib/exec_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/intuition_protos.h>
#ifdef USE_PRAGMAS
#include <proto/exec.h>
#include <proto/gadtools.h>
#include <proto/intuition.h>
#endif
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#define CATCOMP_NUMBERS
#include "args.h"
#include "catalog.h"
#include "common.h"
#include "compiler.h"
#include "cx.h"
#include "gui.h"
#include "message.h"
#include "strings.h"
#include "wb.h"
#define NOT_SET 0xffffffffU
#define GAD_ID_LIST 1
#define GAD_ID_NEW 2
#define GAD_ID_DELETE 3
#define GAD_ID_NAME 4
#define GAD_ID_PATH 5
typedef struct {
int line_h;
int col1_x;
int list_y, list_w, list_h, scro_w;
int gadg_h;
int name_y, butn_y;
int col2_x;
int path_y, path_w;
int wind_w, wind_h;
int text_y;
} Layout;
extern struct IntuitionBase *IntuitionBase;
static struct IntuiText itexts[3] = {
{ 0, 0, JAM1, 0, 0, NULL, NULL, itexts + 1 },
{ 0, 0, JAM1, 0, 0, NULL, NULL, itexts + 2 },
{ 0, 0, JAM1, 0, 0, NULL, NULL, NULL }
};
static WORD zoom[4];
static struct MsgPort *user_port;
static struct Menu *menus;
static struct Requester busy_req;
static Message message;
static Bool message_constructed;
static struct Screen *screen;
static struct DrawInfo *draw_info;
static APTR visual_info;
static struct Gadget *gadgets;
static struct Window *window;
static struct AppWindow *app_window;
static ULONG left_edge;
static ULONG top_edge = NOT_SET;
static struct Gadget *list_gad, *name_gad, *del_gad, *path_gad;
static Tool *current;
static UBYTE *strgad_buf(struct Gadget *gadget)
{
return ((struct StringInfo *) gadget->SpecialInfo)->Buffer;
}
static void strip_messages_for(struct Window *window)
{
struct IntuiMessage *msg, *succ;
msg = (struct IntuiMessage *) window->UserPort->mp_MsgList.lh_Head;
while ((succ = (struct IntuiMessage *) msg->ExecMessage.mn_Node.ln_Succ)
!= NULL) {
if (msg->IDCMPWindow == window) {
Remove(&msg->ExecMessage.mn_Node);
ReplyMsg(&msg->ExecMessage);
}
msg = succ;
}
}
static void close_window_safely(struct Window *window)
{
Forbid();
strip_messages_for(window);
window->UserPort = NULL;
ModifyIDCMP(window, 0);
Permit();
CloseWindow(window);
}
static Bool set_up_menus(void)
{
static struct NewMenu new_menus[] = {
{ NM_TITLE, NULL, NULL, 0, 0, (APTR) MSG_PROJECT_MENU },
{ NM_ITEM, NULL, "S", 0, 0, (APTR) MSG_PROJECT_SAVE },
{ NM_ITEM, NM_BARLABEL, NULL, 0, 0, NULL },
{ NM_ITEM, NULL, "H", 0, 0, (APTR) MSG_PROJECT_HIDE },
{ NM_ITEM, NULL, NULL, 0, 0, (APTR) MSG_PROJECT_ABOUT },
{ NM_ITEM, NULL, "Q", 0, 0, (APTR) MSG_PROJECT_QUIT },
{ NM_END, NULL, NULL, 0, 0, NULL }
};
struct NewMenu *nm;
for (nm = new_menus; nm->nm_Type != NM_END; ++nm)
if (nm->nm_UserData != NULL)
nm->nm_Label = get_string((ULONG) nm->nm_UserData);
if ((menus = CreateMenus(new_menus, TAG_DONE)) == NULL)
return NO;
return YES;
}
static void render(void)
{
PrintIText(window->RPort, itexts, 0, 0);
}
static void make_layout(Layout *layout)
{
int font_w = draw_info->dri_Font->tf_XSize;
int font_h = draw_info->dri_Font->tf_YSize;
int pad_x = font_w;
int pad_y = font_h / 2;
int lab_h = font_h + 4; /* space taken up by label above a gadget */
int path_th; /* total height of path gadget and label above */
int col2_spc; /* vertical spacing around path gadget and text */
layout->line_h = font_h + 1;
layout->col1_x = pad_x;
layout->list_y = pad_y + lab_h;
layout->list_w = 24 * font_w + 12; /* should be divisible by 2 */
layout->list_h = 6 * layout->line_h + 4;
layout->scro_w = font_w + 10;
layout->gadg_h = font_h + 6;
layout->name_y = layout->list_y + layout->list_h;
layout->butn_y = layout->name_y + layout->gadg_h;
layout->col2_x = layout->col1_x + layout->list_w + pad_x;
layout->path_w = 32 * font_w + 12;
layout->wind_w = layout->col2_x + layout->path_w + pad_x;
layout->wind_h = layout->butn_y + layout->gadg_h + pad_y;
path_th = layout->gadg_h + lab_h;
col2_spc = (layout->wind_h - path_th - 3 * layout->line_h) / 3;
layout->path_y = col2_spc + lab_h;
layout->text_y = 2 * col2_spc + path_th;
}
static unsigned window_border_top(void)
{
return screen->WBorTop + screen->Font->ta_YSize + 1U;
}
static void make_newgadget(struct NewGadget *ng, WORD left_edge,
WORD top_edge, WORD width, WORD height, UBYTE *gadget_text, UWORD id,
ULONG flags)
{
ng->ng_LeftEdge = left_edge + screen->WBorLeft;
ng->ng_TopEdge = top_edge + window_border_top();
ng->ng_Width = width;
ng->ng_Height = height;
ng->ng_GadgetText = gadget_text;
ng->ng_GadgetID = id;
ng->ng_Flags = flags;
}
static Bool create_gadgets(Layout *l)
{
struct NewGadget ng;
struct Gadget *g = CreateContext(&gadgets);
int butn_w = l->list_w / 2;
ng.ng_TextAttr = screen->Font;
ng.ng_VisualInfo = visual_info;
make_newgadget(&ng, l->col1_x, l->list_y, l->list_w, l->list_h,
get_string(MSG_GAD_MENU_ITEMS), GAD_ID_LIST, 0);
g = list_gad = CreateGadget(LISTVIEW_KIND, g, &ng,
GTLV_Labels, tools,
GTLV_ScrollWidth, (LONG) l->scro_w,
LAYOUTA_Spacing, 1L,
TAG_DONE);
make_newgadget(&ng, l->col1_x, l->name_y, l->list_w, l->gadg_h,
NULL, GAD_ID_NAME, 0);
g = name_gad = CreateGadget(STRING_KIND, g, &ng,
GA_Disabled, (LONG) TRUE,
TAG_DONE);
make_newgadget(&ng, l->col1_x, l->butn_y, butn_w, l->gadg_h,
get_string(MSG_GAD_NEW), GAD_ID_NEW, 0);
g = CreateGadget(BUTTON_KIND, g, &ng,
TAG_DONE);
make_newgadget(&ng, l->col1_x + butn_w, l->butn_y, butn_w, l->gadg_h,
get_string(MSG_GAD_DELETE), GAD_ID_DELETE, 0);
g = del_gad = CreateGadget(BUTTON_KIND, g, &ng,
GA_Disabled, (LONG) TRUE,
TAG_DONE);
make_newgadget(&ng, l->col2_x, l->path_y, l->path_w, l->gadg_h,
get_string(MSG_GAD_TOOL), GAD_ID_PATH, PLACETEXT_ABOVE);
g = path_gad = CreateGadget(STRING_KIND, g, &ng,
GTST_MaxChars, (LONG) MAX_PATH_LENGTH,
GA_Disabled, (LONG) TRUE,
TAG_DONE);
return g != NULL;
}
static void layout_texts(Layout *layout)
{
int left_edge = layout->col2_x;
int top_edge = layout->text_y + window_border_top();
struct IntuiText *t;
for (t = itexts; t != NULL; t = t->NextText) {
t->FrontPen = draw_info->dri_Pens[TEXTPEN];
t->ITextFont = screen->Font;
t->LeftEdge = left_edge + (layout->path_w - IntuiTextLength(t)) / 2;
t->TopEdge = top_edge;
top_edge += layout->line_h;
}
}
static Bool open_window(Layout *layout)
{
static char window_title_buf[64];
char *window_title = get_string(MSG_WINDOW_TITLE);
if (strlen(window_title)+strlen(APP_NAME)+strlen(args.cx_popkey) > 64)
window_title = APP_NAME;
else {
sprintf(window_title_buf, window_title, APP_NAME, args.cx_popkey);
window_title = window_title_buf;
}
if ((window = OpenWindowTags(NULL,
WA_Left, left_edge,
WA_Top, top_edge,
WA_InnerWidth, (LONG) layout->wind_w,
WA_InnerHeight, (LONG) layout->wind_h,
WA_Flags, (ULONG) WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET |
WFLG_ACTIVATE | WFLG_SIMPLE_REFRESH,
WA_PubScreen, screen,
WA_Zoom, zoom,
WA_Gadgets, gadgets,
WA_Title, window_title,
WA_AutoAdjust, (LONG) TRUE,
WA_NewLookMenus, (LONG) TRUE,
TAG_DONE)) == NULL)
return NO;
window->UserPort = user_port;
ModifyIDCMP(window, IDCMP_CLOSEWINDOW | IDCMP_MENUPICK | IDCMP_REFRESHWINDOW
| LISTVIEWIDCMP | STRINGIDCMP | BUTTONIDCMP);
GT_RefreshWindow(window, NULL);
return YES;
}
static void update_gadgets(void)
{
Bool disable = (current == NULL);
GT_SetGadgetAttrs(name_gad, window, NULL,
GA_Disabled, (LONG) disable,
GTST_String, disable ? "" : current->node.ln_Name,
TAG_DONE);
GT_SetGadgetAttrs(del_gad, window, NULL,
GA_Disabled, (LONG) disable,
TAG_DONE);
GT_SetGadgetAttrs(path_gad, window, NULL,
GA_Disabled, (LONG) disable,
GTST_String, disable ? "" : current->path,
TAG_DONE);
}
static void update_current(void)
{
if (current == NULL)
return;
if ((current = cx_modify_tool(current, strgad_buf(name_gad),
strgad_buf(path_gad))) == NULL)
update_gadgets();
}
static void select(int index)
{
gui_edit((Tool *) node_at(tools, index));
}
static void new_tool(void)
{
cx_add_tool("", "");
}
static void delete_tool(void)
{
GT_SetGadgetAttrs(name_gad, window, NULL,
GTST_String, "",
TAG_DONE);
update_current();
}
static void handle_gadgetup(struct Gadget *gadget, UWORD code)
{
switch (gadget->GadgetID) {
case GAD_ID_LIST:
select(code);
break;
case GAD_ID_NEW:
new_tool();
break;
case GAD_ID_DELETE:
delete_tool();
break;
case GAD_ID_NAME:
case GAD_ID_PATH:
update_current();
break;
}
}
static void handle_project_menu(UWORD code)
{
switch (ITEMNUM(code)) {
case 0: /* Save Menu Items */
cx_save_tools();
break;
case 2: /* Hide */
cx_hide();
break;
case 3: /* About */
cx_about();
break;
case 4: /* Quit */
cx_quit();
break;
}
}
static void handle_menupick(UWORD code)
{
while (code != MENUNULL) {
switch (MENUNUM(code)) {
case 0:
handle_project_menu(code);
break;
}
code = ItemAddress(menus, code)->NextSelect;
}
}
static void handle_closewindow(void)
{
cx_hide();
}
static void handle_refreshwindow(void)
{
GT_BeginRefresh(window);
render();
GT_EndRefresh(window, TRUE);
}
static void bring_to_front(void)
{
ScreenToFront(window->WScreen);
WindowToFront(window);
ActivateWindow(window);
if (window->Height == zoom[3])
ZipWindow(window);
}
static void fill_itexts(struct IntuiText *text, va_list *ap)
{
char *s;
while ((s = va_arg(*ap, char *)) != NULL) {
text->IText = s;
text->NextText = text + 1;
++text;
}
(text - 1)->NextText = NULL;
}
ULONG gui_set_up()
{
if (IntuitionBase->LibNode.lib_Version >= 39)
zoom[0] = zoom[1] = ~0;
if (!set_up_menus())
exit(RETURN_FAIL);
if ((user_port = CreateMsgPort()) == NULL)
exit(RETURN_FAIL);
itexts[0].IText = get_string(MSG_INFO_1);
itexts[1].IText = get_string(MSG_INFO_2);
itexts[2].IText = get_string(MSG_INFO_3);
InitRequester(&busy_req);
if (!message_cons(&message))
exit(RETURN_FAIL);
message_constructed = YES;
return 1UL << user_port->mp_SigBit;
}
void gui_clean_up()
{
if (message_constructed)
message_dest(&message);
DeleteMsgPort(user_port);
if (menus != NULL) /* Really checking if gadtools.library was opened */
FreeMenus(menus);
}
void gui_handle_signal()
{
struct IntuiMessage *imsg;
ULONG clas;
UWORD code;
APTR iadd;
while ((imsg = GT_GetIMsg(user_port)) != NULL) {
clas = imsg->Class;
code = imsg->Code;
iadd = imsg->IAddress;
GT_ReplyIMsg(imsg);
switch (clas) {
case IDCMP_MENUPICK:
handle_menupick(code);
break;
case IDCMP_CLOSEWINDOW:
handle_closewindow();
break;
case IDCMP_REFRESHWINDOW:
handle_refreshwindow();
break;
case IDCMP_GADGETUP:
handle_gadgetup(iadd, code);
break;
}
}
}
void gui_show()
{
Layout layout;
if (window != NULL) {
bring_to_front();
return;
}
if ((screen = LockPubScreen(NULL)) == NULL)
goto gui_show_failed;
ScreenToFront(screen);
if ((draw_info = GetScreenDrawInfo(screen)) == NULL)
goto gui_show_failed;
if ((visual_info = GetVisualInfo(screen, TAG_DONE)) == NULL)
goto gui_show_failed;
if (!LayoutMenus(menus, visual_info,
GTMN_NewLookMenus, (LONG) TRUE,
TAG_DONE))
goto gui_show_failed;
if (top_edge == NOT_SET)
top_edge = screen->BarHeight + 1;
zoom[2] = 25 * draw_info->dri_Font->tf_XSize;
zoom[3] = window_border_top();
make_layout(&layout);
if (!create_gadgets(&layout))
goto gui_show_failed;
layout_texts(&layout);
if (!open_window(&layout))
goto gui_show_failed;
render();
app_window = wb_add_window(window);
SetMenuStrip(window, menus);
current = NULL;
return;
gui_show_failed:
gui_hide();
}
void gui_hide()
{
if (app_window != NULL) {
wb_remove_window(app_window);
app_window = NULL;
}
if (window != NULL) {
EndRequest(&message.requester, window);
if (window->MenuStrip != NULL)
ClearMenuStrip(window);
left_edge = window->LeftEdge;
top_edge = window->TopEdge;
close_window_safely(window);
window = NULL;
}
FreeGadgets(gadgets);
gadgets = NULL;
FreeVisualInfo(visual_info);
visual_info = NULL;
if (screen != NULL) {
FreeScreenDrawInfo(screen, draw_info);
draw_info = NULL;
UnlockPubScreen(NULL, screen);
screen = NULL;
}
}
void gui_edit(Tool *tool)
{
if (window == NULL)
return;
current = tool;
update_gadgets();
if (current != NULL)
ActivateGadget(name_gad, window, NULL);
}
/* Temporarily suspend the listview so we can update the list. */
void gui_begin_update()
{
if (window == NULL)
return;
GT_SetGadgetAttrs(list_gad, window, NULL, GTLV_Labels, ~0L, TAG_DONE);
}
/* Resume normal listview operations. */
void gui_end_update()
{
if (window == NULL)
return;
GT_SetGadgetAttrs(list_gad, window, NULL, GTLV_Labels, tools, TAG_DONE);
}
void gui_begin_busy()
{
static UWORD CHIP busy_pointer[] = {
0x0000, 0x0000, 0x0400, 0x07c0, 0x0000, 0x07c0, 0x0100, 0x0380,
0x0000, 0x07e0, 0x07c0, 0x1ff8, 0x1ff0, 0x3fec, 0x3ff8, 0x7fde,
0x3ff8, 0x7fbe, 0x7ffc, 0xff7f, 0x7efc, 0xffff, 0x7ffc, 0xffff,
0x3ff8, 0x7ffe, 0x3ff8, 0x7ffe, 0x1ff0, 0x3ffc, 0x07c0, 0x1ff8,
0x0000, 0x07e0, 0x0000, 0x0000
};
if (window == NULL)
return;
Request(&busy_req, window);
if (IntuitionBase->LibNode.lib_Version < 39)
SetPointer(window, busy_pointer, 16, 16, -6, 0);
else
SetWindowPointer(window,
WA_BusyPointer, (LONG) TRUE,
WA_PointerDelay, (LONG) TRUE,
TAG_DONE);
}
void gui_end_busy()
{
if (window == NULL)
return;
if (IntuitionBase->LibNode.lib_Version < 39)
ClearPointer(window);
else
SetWindowPointer(window, TAG_DONE);
EndRequest(&busy_req, window);
}
void gui_message(char *button_text, ...)
{
static struct IntuiText texts[GUI_MESSAGE_MAX_LINES];
va_list ap;
va_start(ap, button_text);
if (window == NULL || message.requester.Flags & REQACTIVE)
goto gui_message_exit;
fill_itexts(texts, &ap);
message_layout(&message, window, draw_info, texts, button_text);
Request(&message.requester, window);
gui_message_exit:
va_end(ap);
}