peilaus alkaen https://frontier.innolan.net/rainlance/ToolsMenu.git
619 rivejä
16 KiB
C
Executable File
619 rivejä
16 KiB
C
Executable File
/*
|
|
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);
|
|
}
|