diff options
Diffstat (limited to 'src/gui_amiga.c')
-rw-r--r-- | src/gui_amiga.c | 1795 |
1 files changed, 1795 insertions, 0 deletions
diff --git a/src/gui_amiga.c b/src/gui_amiga.c new file mode 100644 index 000000000..28786aa6f --- /dev/null +++ b/src/gui_amiga.c @@ -0,0 +1,1795 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * Amiga GUI support by Michael Nielsen + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +#include <stdlib.h> +#include <string.h> +#include <exec/types.h> +#include <intuition/intuition.h> +#include <utility/tagitem.h> +#include <graphics/text.h> +#include <graphics/rastport.h> +#include <graphics/layers.h> +#include <proto/intuition.h> +#include <proto/graphics.h> +#include <proto/layers.h> +#include <devices/timer.h> +#include <assert.h> +#include "vim.h" +#include "gui_amiga.h" +#include <math.h> +#include <limits.h> + +#ifdef __AROS__ +#include <aros/debug.h> +#endif + +#include "version.h" + +#if defined(FEAT_GUI_AMIGA) || defined(PROTO) + +#define KEYUP 76 +#define KEYDOWN 77 +#define KEYRIGHT 78 +#define KEYLEFT 79 +#define KEYBACKSPACE 0x41 +#define KEYDELETE 0x46 +#define KEYINSERT 0x47 +#define KEYHOME 0x70 +#define KEYEND 0x71 +#define KEYWHEELUP 0x7A +#define KEYWHEELDOWN 0x7B + +/* When generating prototypes on Unix, these need to be defined */ +#ifdef PROTO +# define STRPTR char * +# define BOOL int +# define UBYTE int +#endif + +static struct PropInfo Gadget2SInfo = { AUTOKNOB+PROPBORDERLESS+FREEVERT+PROPNEWLOOK, 0, 0, MAXBODY, MAXBODY, }; +//static struct Image Image1 = { 0, 0, 10, 397, 0, NULL, 0x0000, 0x0000, NULL }; +static struct Gadget propGadget = { NULL, -12, 15, 10, -28, + GFLG_RELRIGHT+GFLG_RELHEIGHT, + GACT_RELVERIFY+GACT_RIGHTBORDER+GACT_IMMEDIATE, + GTYP_PROPGADGET+GTYP_GZZGADGET, + NULL, NULL, + NULL, NULL, (APTR)&Gadget2SInfo, NULL, NULL }; + +static struct timerequest *TimerIO; +static struct MsgPort *TimerMP; +static BOOL TimerSent; + +struct GFXBase *gfxBase; +struct ExecBase *execBase; +struct LayersBase *layersBase; + +struct MyColor +{ + WORD pen; + BOOL alloced; +}; + +struct MyColor MyColorTable[256]; + +struct TagItem tags[] = +{ + {WA_Left, 0}, + {WA_Top, 0}, + {WA_Width, 400}, + {WA_Height, 400}, + {WA_Title, (ULONG)VIM_VERSION_SHORT}, + {WA_ScreenTitle, (ULONG)VIM_VERSION_LONG}, + {WA_DragBar, TRUE}, /* enable dragging of the window */ + {WA_DepthGadget, TRUE}, /* enable the depth gadget */ + {WA_CloseGadget, TRUE}, /* enable the close gadget*/ + {WA_SizeGadget, TRUE}, /* enable the size gadget */ + {WA_SizeBBottom, TRUE}, /* sizegadget contained in bottom border */ + {WA_SmartRefresh, TRUE}, /* choose smart refresh, saves us doing a lot of work */ + {WA_ReportMouse, TRUE}, /* Report the position of the mouse */ + {WA_GimmeZeroZero, TRUE}, + {WA_Activate, TRUE}, /* Activate window on startup */ + {WA_Activate, TRUE}, /* Activate window on startup */ + {WA_NoCareRefresh, TRUE}, /* Refresh screen, don't tell us */ + {WA_NewLookMenus, TRUE}, /* use the new options for the menu */ + {WA_AutoAdjust, TRUE}, /* If window is too big for screen adjust size*/ + {WA_NoCareRefresh, TRUE}, /* If window is too big for screen adjust size*/ + {WA_MouseQueue, 1}, /* Limit number of pending mouse movement*/ + {WA_RptQueue, 10}, /* Limit number of pending keystrokes*/ + {WA_IDCMP, /* IDCMP, what events interest us */ + IDCMP_NEWSIZE /* Notify us about size change of window*/ + |IDCMP_REFRESHWINDOW /* Notify us when the window needs refreshing */ + |IDCMP_MOUSEBUTTONS /* Notify us when the mouse buttons have been used */ + |IDCMP_MOUSEMOVE /* Notify us when the mouse is moving */ + |IDCMP_GADGETDOWN /* Notify us when a gadget has been selected */ + |IDCMP_GADGETUP /* Notify us when a gadget has been released */ + |IDCMP_MENUPICK /* Notify us when a menu has been picked */ + |IDCMP_CLOSEWINDOW /* Notify us when the user tries to close the window */ + |IDCMP_VANILLAKEY /* Notify us about keystrokes */ + |IDCMP_RAWKEY /* Notify us when raw key events have been used, ie cursor*/ + |IDCMP_INTUITICKS /* Simpler timer for the blink option */ + |IDCMP_MENUHELP /* Allow the help key to be used during menu events */ + |IDCMP_GADGETHELP /* Allow the help key to be used during gadget events */ + |IDCMP_INACTIVEWINDOW /* notify of inactive window */ + |IDCMP_ACTIVEWINDOW /* notify of inactive window */ + }, + {TAG_DONE, NULL} +}; + +#if defined(D) +#undef D +#endif + +/*#define D(_msg) fprintf(stderr, "%s\n", _msg)*/ + +#define D(_A) +#define kprintf(s, ...) + +static void AmigaError(const char *string); + +void HandleEvent(unsigned long * object); +static UBYTE getrealcolor(guicolor_T i); + +static struct NewWindow vimNewWindow = +{ + 0, 0, /* window XY origin relative to TopLeft of screen */ + 0, 0, /* window width and height */ + 0, 1, /* detail and block pens */ + NULL, /* IDCMP flags */ + NULL, /* other window flags */ + &propGadget, /* first gadget in gadget list */ + NULL, /* custom CHECKMARK imagery */ + "Amiga Vim gui", /* window title */ + NULL, /* custom screen pointer */ + NULL, /* custom bitmap */ + 50, 50, /* minimum width and height */ + (unsigned short)-1, (unsigned short)-1, /* maximum width and height */ + WBENCHSCREEN /* destination screen type */ +}; + +static struct +{ + unsigned int key_sym; + char_u vim_code0; + char_u vim_code1; +} special_keys[] = +{ + {0, 0, 0} +}; + +#if 0 + /* not used? */ + static int +hex_digit(int c) +{ + if (isdigit(c)) + return c - '0'; + c = TOLOWER_ASC(c); + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + return -1000; +} +#endif + +static int characterWidth = -1; +static int characterHeight = -1; +static struct +{ + BOOL active; + enum + { + CursorOff, + CursorOn, + CursorWait + } state; + int onTime; + int offTime; + int waitTime; + int current; +} cursor = +{ + TRUE, + CursorWait, + 10, + 10, + 7, + 0 +}; + +enum DrawBoxMode +{ + DB_Filled, + DB_NotFilled +}; + + static void +TextDimensions(void) +{ + struct TextExtent textExt; + + TextExtent(gui.window->RPort, "s", 1, &textExt); + + characterWidth = textExt.te_Width; + characterHeight = textExt.te_Height; +} + + static int +posWidthCharToPoint(int width) +{ + return (width)*characterWidth; +} + + static int +posHeightCharToPoint(int height) +{ + return (int)(height)*characterHeight; +} + + static int +posWidthPointToChar(int width) +{ + //return (int)floor((float)width/(float)characterWidth)-1; + return width /characterWidth; +} + + static int +posHeightPointToChar(int height) +{ + //return (int)floor((float)height/(float)characterHeight)-2; + return height / characterHeight; +} + + static int +widthCharToPoint(int width) +{ + return (width)*(characterWidth); +} + + static int +heightCharToPoint(int height) +{ + return (height)*characterHeight; +} + + static int +widthPointToChar(int width) +{ + return (width)/characterWidth; +} + + static int +heightPointToChar(int height) +{ + return (height)/characterHeight; +} + + static void +refreshBorder(void) +{ + /*WaitBOVP(gui.window->);*/ + RefreshWindowFrame(gui.window); +} + + static void +drawBox(enum DrawBoxMode mode, unsigned short col, unsigned short row, int w, int h, guicolor_T color) +{ + LONG apen = GetAPen(gui.window->RPort); + LONG x1, y1, x2, y2; + +kprintf(" drawbox %d,%d color %d\n", col, row, color); + + SetAPen(gui.window->RPort, getrealcolor(color)); + + x1 = posWidthCharToPoint(col); + y1 = posHeightCharToPoint(row + 1) - h; + x2 = x1 + w - 1; + y2 = posHeightCharToPoint(row + 1) - 1; + + switch(mode) + { + case DB_Filled: + RectFill(gui.window->RPort, x1, y1, x2, y2); + break; + + case DB_NotFilled: + Move(gui.window->RPort, x1, y1); + Draw(gui.window->RPort, x2, y1); + Draw(gui.window->RPort, x2, y2); + Draw(gui.window->RPort, x1, y2); + Draw(gui.window->RPort, x1, y1); + break; + } + + SetAPen(gui.window->RPort, apen); + +} + + static enum event +EventHandler(void) +{ + struct IntuiMessage *msg; + enum event returnEvent = ev_Ignore; + int class, code; + static int dragging = 0; + static int mouseX, mouseY; + char_u string[40]; + BOOL quit_request = FALSE; + + msg = (struct IntuiMessage *)GetMsg(gui.window->UserPort); + + if (!msg) + { + returnEvent = ev_NullEvent; + } + else + { + + class = msg->Class; + code = msg->Code; + + switch(class) + { + case IDCMP_INTUITICKS: + /* + if (cursor.active) + { + cursor.current ++; + if (cursor.state == CursorOff) + { + printf("cursor turned on\n"); + if (cursor.offTime < cursor.current) + { + gui_undraw_cursor(); + cursor.state = CursorOn; + cursor.current = 0; + } + } + else if (cursor.state == CursorOn) + { + printf("cursor turned off\n"); + if (cursor.onTime < cursor.current) + { + cursor.state = CursorOff; + gui_update_cursor(FALSE); + cursor.current = 0; + } + } + else if (cursor.state == CursorWait) + { + printf("cursor turned Wait\n"); + if (cursor.waitTime < cursor.current) + { + cursor.state = CursorOn; + cursor.current = 0; + } + } + } + else + { + } + returnEvent = ev_IntuiTicks; + */ + break; + + case IDCMP_MOUSEBUTTONS: + { + int vim_modifiers=0; + D("Mouse button event detected"); + switch (msg->Qualifier ) + { + case IEQUALIFIER_LALT: + case IEQUALIFIER_RALT: + D("detected a Alt key"); + vim_modifiers|=MOUSE_ALT; + break; + + case IEQUALIFIER_LSHIFT: + case IEQUALIFIER_RSHIFT: + D("detected a Shift key"); + vim_modifiers|=MOUSE_SHIFT; + break; + case IEQUALIFIER_CONTROL: + D("detected a Control key"); + vim_modifiers |= MOUSE_CTRL; + break; + } + if (code == SELECTDOWN) + { + D("Select Down detected\n"); + dragging = 1; + gui_send_mouse_event(MOUSE_LEFT, + mouseX = msg->MouseX - gui.window->BorderLeft, + mouseY = msg->MouseY - gui.window->BorderTop, + FALSE, + vim_modifiers); + /*gui_start_highlight(HL_ALL);*/ + } + else if (code == SELECTUP) + { + D("Select UP detected\n"); + dragging = 0; + gui_send_mouse_event(MOUSE_RELEASE, + msg->MouseX - gui.window->BorderLeft, + msg->MouseY - gui.window->BorderTop, + FALSE, vim_modifiers); + /*gui_stop_highlight(mask);*/ + } + returnEvent = ev_MouseButtons; + break; + } + case IDCMP_MOUSEMOVE: + if ((abs(mouseX-(msg->MouseX - gui.window->BorderLeft)) > characterWidth) || + (abs(mouseY-(msg->MouseY - gui.window->BorderTop))>characterHeight)) + { + int vim_modifiers=0; + + switch (msg->Qualifier ) + { + case IEQUALIFIER_LALT: + case IEQUALIFIER_RALT: + D("detected a Alt key"); + vim_modifiers|=MOUSE_ALT; + break; + + case IEQUALIFIER_LSHIFT: + case IEQUALIFIER_RSHIFT: + D("detected a Shift key"); + vim_modifiers|=MOUSE_SHIFT; + break; + case IEQUALIFIER_CONTROL: + D("detected a Control key"); + vim_modifiers |= MOUSE_CTRL; + break; + } + + mouseX = msg->MouseX - gui.window->BorderLeft; + mouseY = msg->MouseY - gui.window->BorderTop; + if (!dragging) + { + gui_send_mouse_event(MOUSE_SETPOS, mouseX, mouseY, FALSE, vim_modifiers); + break; + } + else + { + D("dragging\n"); + gui_send_mouse_event(MOUSE_DRAG, mouseX, mouseY, FALSE, vim_modifiers); + } + } + returnEvent = ev_MouseMove; + break; + case IDCMP_VANILLAKEY: +kprintf("===vanillakey %d\n", code); + { + string[0] = (char_u)code; + if (code == CSI) + { + /* Insert CSI as K_CSI. Untested! */ + string[1] = KS_EXTRA; + string[2] = (int)KE_CSI; + add_to_input_buf(string, 3); + } + else if (code == 8) + { + string[0] = CSI; + string[1] = 'k'; + string[2] = 'b'; + add_to_input_buf(string, 3); + } + else if (code == 127) + { + string[0] = CSI; + string[1] = 'k'; + string[2] = 'D'; + add_to_input_buf(string, 3); + } + else + { + int len = 1; + + if (input_conv.vc_type != CONV_NONE) + len = convert_input(string, 1, sizeof(string)); + add_to_input_buf(string, len); + } + returnEvent = ev_KeyStroke; + break; + + case IDCMP_RAWKEY: + if (msg->Qualifier & IEQUALIFIER_LSHIFT) + { + } + else if (msg->Qualifier & IEQUALIFIER_RSHIFT) + { + } + else if (msg->Qualifier & IEQUALIFIER_CONTROL) + { + if (code == 33) + { + trash_input_buf(); + } + } + else if (msg->Code == KEYUP) + { + string[0] = CSI; + string[1] = 'k'; + string[2] = 'u'; + add_to_input_buf(string, 3); + } + else if (msg->Code == KEYLEFT) + { + string[0] = CSI; + string[1] = 'k'; + string[2] = 'l'; + add_to_input_buf(string, 3); + } + else if (msg->Code == KEYRIGHT) + { +kprintf("## keyright"); + string[0] = CSI; + string[1] = 'k'; + string[2] = 'r'; + add_to_input_buf(string, 3); + } + else if (msg->Code == KEYDOWN) + { + string[0] = CSI; + string[1] = 'k'; + string[2] = 'd'; + add_to_input_buf(string, 3); + } + else if (msg->Code == KEYBACKSPACE) + { + string[0] = CSI; + string[1] = 'k'; + string[2] = 'b'; + add_to_input_buf(string, 3); + } + else if (msg->Code == KEYDELETE) + { + string[0] = CSI; + string[1] = 'k'; + string[2] = 'D'; + add_to_input_buf(string, 3); + } + else if (msg->Code == KEYINSERT) + { + string[0] = CSI; + string[1] = 'k'; + string[2] = 'I'; + add_to_input_buf(string, 3); + } + else if (msg->Code == KEYHOME) + { + string[0] = CSI; + string[1] = 'k'; + string[2] = 'h'; + add_to_input_buf(string, 3); + } + else if (msg->Code == KEYEND) + { + string[0] = CSI; + string[1] = '@'; + string[2] = '7'; + add_to_input_buf(string, 3); + } + else if (msg->Code == KEYWHEELUP) + { + int vim_modifiers=0; + + switch (msg->Qualifier ) + { + case IEQUALIFIER_LALT: + case IEQUALIFIER_RALT: + D("detected a Alt key"); + vim_modifiers|=MOUSE_ALT; + break; + + case IEQUALIFIER_LSHIFT: + case IEQUALIFIER_RSHIFT: + D("detected a Shift key"); + vim_modifiers|=MOUSE_SHIFT; + break; + case IEQUALIFIER_CONTROL: + D("detected a Control key"); + vim_modifiers |= MOUSE_CTRL; + break; + } + gui_send_mouse_event(MOUSE_4, 0, 1, FALSE, vim_modifiers); + + } + else if (msg->Code == KEYWHEELDOWN) + { + int vim_modifiers=0; + + switch (msg->Qualifier ) + { + case IEQUALIFIER_LALT: + case IEQUALIFIER_RALT: + D("detected a Alt key"); + vim_modifiers|=MOUSE_ALT; + break; + + case IEQUALIFIER_LSHIFT: + case IEQUALIFIER_RSHIFT: + D("detected a Shift key"); + vim_modifiers|=MOUSE_SHIFT; + break; + case IEQUALIFIER_CONTROL: + D("detected a Control key"); + vim_modifiers |= MOUSE_CTRL; + break; + } + gui_send_mouse_event(MOUSE_5, 0, 1, FALSE, vim_modifiers); + } + + returnEvent = ev_KeyStroke; + break; + } + case IDCMP_MENUVERIFY: + returnEvent = ev_MenuVerify; + /* Menu verification requested */ + switch (code) + { + case MENUWAITING: + /* + ** It's not for us, the user is accessing another + ** programs menu, this is a good time to do some + ** cleanup etc + */ + break; + case MENUHOT: + /* + ** It is our menu that is going hot, we have kontrol + ** Menu action can be cancelled by + ** msg->Code = MENUCANCEL; + */ + break; + default: + break; + } + break; + case IDCMP_MENUPICK: + returnEvent = ev_MenuPick; + { + /* + ** one of our menu's have been selected, let's find out which + */ + union myMenuItemUnion *item; + int menuNumber; + + menuNumber = code; + + item = (union myMenuItemUnion *) ItemAddress(gui.menu, menuNumber); + + + if (item) + { + gui_menu_cb(item->myMenuItem.guiMenu); + } + } + break; + case IDCMP_CLOSEWINDOW: + quit_request = TRUE; + break; + + case IDCMP_NEWSIZE: + { + int cx, cy; + //cx = widthPointToChar(gui.window->GZZWidth); + //cy = heightPointToChar(gui.window->GZZHeight); + + cx = gui.window->GZZWidth; + cy = gui.window->GZZHeight - characterHeight; + + gui_resize_shell(cx, cy); + + returnEvent = ev_NewSize; + break; + } + case IDCMP_REFRESHWINDOW: + refreshBorder(); + returnEvent = ev_RefreshWindow; + break; + case IDCMP_GADGETDOWN: + returnEvent = ev_GadgetDown; + break; + case IDCMP_GADGETUP: + returnEvent = ev_GadgetUp; + break; + case IDCMP_MENUHELP: + returnEvent = ev_MenuHelp; + break; + case IDCMP_GADGETHELP: + returnEvent = ev_GadgetHelp; + break; + case IDCMP_INACTIVEWINDOW: + gui.in_focus = FALSE; + gui_update_cursor(TRUE, FALSE); + break; + + case IDCMP_ACTIVEWINDOW: + gui.in_focus = TRUE; + gui_update_cursor(TRUE, FALSE); + break; + default: + break; + } + ReplyMsg((struct Message*)msg); + } + + if (quit_request) + { + getout(0); // gui_mch_exit(1); + } + + return returnEvent; + /* mouse positin gui.window->MoseY, gui.window->MouseX) */ +} + + static int +checkEventHandler(void) +{ + enum event happened; + + do + { + happened = EventHandler() ; + } + while (happened != ev_NullEvent); + + return OK; +} + + static int +charEventHandler(int wtime) +{ + enum event happened; + int rc; + + do + { + Wait(1<<gui.window->UserPort->mp_SigBit); + + happened = EventHandler() ; + } + while ((happened != ev_IntuiTicks) && (happened != ev_KeyStroke) && (happened != ev_MenuPick) && (happened != ev_MouseMove) &&(happened != ev_MouseButtons) ); + + if (happened == ev_KeyStroke || happened == ev_MenuPick) + rc = OK; + else + rc = FAIL; + + return rc; +} + + +/* + * add primary menu + */ + void +gui_mch_add_menu_item(vimmenu_T *menu, int idx) +{ + union myMenuItemUnion *menuItemUnion = NULL; + struct IntuiText *menutext = NULL; + vimmenu_T *parent; + + assert(menu != NULL); + assert(menu->parent != NULL); + parent = menu->parent; + + /* Don't add menu separator */ + if (menu_is_separator(menu->name)) + return; + + if (parent->menuItemPtr == NULL) + return; + + /* TODO: use menu->mnemonic and menu->actext */ + menutext = (struct IntuiText *) malloc(sizeof(struct IntuiText)); + + SetAttrib(menutext, FrontPen, 3); + SetAttrib(menutext, BackPen, 1); + SetAttrib(menutext, DrawMode, COMPLEMENT); + SetAttrib(menutext, LeftEdge, 0); + SetAttrib(menutext, TopEdge, 0); + SetAttrib(menutext, ITextFont, NULL); + SetAttrib(menutext, NextText, NULL); + + menuItemUnion = malloc(sizeof(*menuItemUnion)); + + SetAttrib(&menuItemUnion->menuItem, NextItem, parent->menuItemPtr); + SetAttrib(&menuItemUnion->menuItem, LeftEdge, 0); + SetAttrib(&menuItemUnion->menuItem, Width, characterWidth*strlen(menu->dname)); + SetAttrib(&menuItemUnion->menuItem, Height, characterHeight+2); + SetAttrib(&menuItemUnion->menuItem, Flags, ITEMTEXT+ITEMENABLED+HIGHCOMP); + SetAttrib(&menuItemUnion->menuItem, MutualExclude, 0); + SetAttrib(&menuItemUnion->menuItem, ItemFill, (APTR)menutext); + SetAttrib(&menuItemUnion->menuItem, SelectFill, NULL); + SetAttrib(&menuItemUnion->menuItem, Command, NULL); + SetAttrib(&menuItemUnion->menuItem, SubItem, NULL); + SetAttrib(&menuItemUnion->menuItem, NextSelect, MENUNULL); + + menutext->IText = malloc(strlen(menu->dname) + 1); + + strcpy(menutext->IText, menu->dname); + + menuItemUnion->menuItem.NextItem = NULL; + + + if (parent) + { + if (!parent->menuItemPtr) + { + D("Adding first subElement"); + SetAttrib(&menuItemUnion->menuItem, TopEdge, 0); + parent->menuPtr->FirstItem = &menuItemUnion->menuItem; + parent->menuItemPtr = &menuItemUnion->menuItem; + } + else + { + struct MenuItem *tmpMenuItem; + tmpMenuItem = parent->menuItemPtr; + while (tmpMenuItem->NextItem) + { + tmpMenuItem = tmpMenuItem->NextItem; + } + tmpMenuItem->NextItem = &menuItemUnion->menuItem; + SetAttrib(&menuItemUnion->menuItem, TopEdge, tmpMenuItem->TopEdge+tmpMenuItem->Height); + } + } + menu->menuPtr= NULL; + menu->menuItemPtr = &menuItemUnion->menuItem; + menuItemUnion->myMenuItem.guiMenu = menu; +} + + + static struct Menu * +getMenu(struct RastPort *rast, int left, STRPTR name) +{ + struct Menu *menu; + struct TextExtent textExt; + + menu = malloc(sizeof(*menu)); + menu->NextMenu = NULL; + menu->LeftEdge = left; + + TextExtent(rast, name, strlen(name), &textExt); + + menu->TopEdge = 0; + menu->Width = textExt.te_Width; + menu->Height = textExt.te_Height; + menu->Flags = ITEMTEXT+HIGHCOMP+MENUENABLED; + menu->MenuName = name; + menu->FirstItem = NULL; + + return menu; +} + +/* + * add 1st level submenu item + */ + void +gui_mch_add_menu(vimmenu_T *menu, int idx) +{ + struct Menu *newMenu; + int pos = 0; + + if (!menu_is_menubar(menu->name)) + return; + + menu->menuPtr = newMenu = getMenu(gui.window->RPort, 0, menu->dname); + menu->menuItemPtr = NULL; + newMenu->NextMenu = NULL; + + if (!gui.menu) + { + D("Adding head menu"); + gui.menu = newMenu ; + } + else + { + struct Menu *tmpMenu; + + tmpMenu = gui.menu; + while (tmpMenu->NextMenu) + tmpMenu = tmpMenu->NextMenu; + tmpMenu->NextMenu = newMenu; + pos = tmpMenu->LeftEdge + + TextLength(gui.window->RPort, tmpMenu->MenuName, + strlen(tmpMenu->MenuName)); + newMenu->LeftEdge = pos; + } +} + + void +gui_mch_toggle_tearoffs(enable) + int enable; +{ + /* no tearoff menus */ +} + + int +gui_mch_set_blinking(long wait, long on, long off) +{ + cursor.waitTime = wait/100; + cursor.onTime = on/100; + cursor.offTime = off/100; + return OK; +} + + void +gui_mch_prepare(int *argc, char **argv) +{ + D("gui_mch_prepare"); + + execBase = (struct ExecBase *)OpenLibrary("exec.library", NULL); + gfxBase = (struct GFXBase *)OpenLibrary("graphics.library", NULL); + layersBase = (struct LayersBase *)OpenLibrary("layers.library", NULL); + + if (!execBase) + { + D("Cannot open exec.library, aborting"); + } + if (!gfxBase) + { + D("Cannot open graphics.library, aborting"); + } + if (!layersBase) + { + D("Cannot open graphics.library, aborting"); + } + D("gui_mch_prepare done "); +} + + void +atexitDoThis(void) +{ +kprintf("atexitdothis###\n"); + gui_mch_exit(-1); +} + +/* + * Check if the GUI can be started. Called before gvimrc is sourced. + * Return OK or FAIL. + */ + int +gui_mch_init_check(void) +{ + if (execBase && gfxBase && layersBase) + return OK; + return FAIL; +} + + int +gui_mch_init(void) +{ + int returnCode = FAIL; /* assume failure*/ + + TimerMP = CreateMsgPort(); + if (!TimerMP) return FAIL; + + TimerIO = (struct timerequest *)CreateIORequest(TimerMP, sizeof(*TimerIO)); + if (!TimerIO) return FAIL; + + if (OpenDevice("timer.device", UNIT_VBLANK, &TimerIO->tr_node, 0)) return FAIL; + + gui.window = OpenWindowTagList(&vimNewWindow, tags); + if (gui.window) + { + gui.in_use = TRUE; + gui.in_focus=TRUE; + gui.norm_pixel = gui.def_norm_pixel = 1; + gui.back_pixel = gui.def_back_pixel = 0; + + set_normal_colors(); + gui_check_colors(); + + SetDrMd(gui.window->RPort, JAM2); + gui_mch_set_colors(gui.norm_pixel, gui.back_pixel); + + atexit(atexitDoThis); + + TextDimensions(); + returnCode = OK; /* we've had success */ + if (gui_win_x != -1 && gui_win_y != -1) + gui_mch_set_winpos(gui_win_x, gui_win_y); + + gui_mch_clear_all(); + + } + gui.menu = NULL; + + return returnCode; +} + + void +gui_mch_new_colors(void) +{ +kprintf("### gui_mch_new_colors\n"); + SetAPen(gui.window->RPort, getrealcolor(gui.norm_pixel)); + SetBPen(gui.window->RPort, getrealcolor(gui.back_pixel)); + + D("gui_mch_new_colors"); +} + + int +gui_mch_open(void) +{ + D("gui_mch_open"); + + highlight_gui_started(); + return OK; +} + + void +gui_mch_exit(int returnCode) +{ +kprintf("###gui_mch_exit\n"); + D("****gui_mch_exit"); + + if (TimerSent) + { + if (!CheckIO(&TimerIO->tr_node)) AbortIO(&TimerIO->tr_node); + WaitIO(&TimerIO->tr_node); + TimerSent = FALSE; + } + + if (TimerIO) + { + CloseDevice(&TimerIO->tr_node); + DeleteIORequest(&TimerIO->tr_node); + TimerIO = NULL; + } + + if (TimerMP) + { + DeleteMsgPort(TimerMP); + TimerMP = NULL; + } + + if (gui.window) + { + int i; + + for(i = 0; i < sizeof(MyColorTable) / sizeof(MyColorTable[0]); i++) + { + if (MyColorTable[i].alloced) + { + ReleasePen(gui.window->WScreen->ViewPort.ColorMap, MyColorTable[i].pen); + MyColorTable[i].alloced = FALSE; + } + } + + D("Closeing window "); + CloseWindow(gui.window); + CloseLibrary((struct Library*)execBase); + CloseLibrary((struct Library*)gfxBase); + gui.window = NULL; + gui.in_use = FALSE; + //getout(1); + } +} + +/* + * Get the position of the top left corner of the window. + */ + int +gui_mch_get_winpos(int *x, int *y) +{ + if (gui.window) + { + *x = gui.window->LeftEdge; + *y = gui.window->TopEdge; + } + else + { + return FAIL; + } + + return OK; +} + +/* + * Set the position of the top left corner of the window to the given + * coordinates. + */ + void +gui_mch_set_winpos(int x, int y) +{ + if (gui.window) + { + ChangeWindowBox(gui.window, x, y, gui.window->Width, gui.window->Height); + } +} + + void +gui_mch_set_shellsize(int width, int height, + int min_width, int min_height, int base_width, int base_height) +{ + D("gui_mch_set_shellsize"); + + ChangeWindowBox(gui.window, gui.window->LeftEdge, + gui.window->TopEdge, widthCharToPoint(width) + gui.window->BorderLeft + gui.window->BorderRight, + heightCharToPoint(height) + gui.window->BorderTop + gui.window->BorderBottom); + checkEventHandler(); +} + + void +gui_mch_get_screen_dimensions(int *screen_w, int *screen_h) +{ +// *screen_w = widthPointToChar(gui.window->GZZWidth); +// *screen_h = heightPointToChar(gui.window->GZZHeight); + *screen_w = gui.window->GZZWidth; + *screen_h = gui.window->GZZHeight - characterHeight; + + +kprintf("=== get_screen_dimensions: screen %d,%d character %d,%d console %d,%d\n", +gui.window->GZZWidth, +gui.window->GZZHeight, +characterWidth, +characterHeight, +*screen_w, +*screen_h); + +} + + void +gui_mch_set_text_area_pos(int x, int y, int w, int h) +{ + D("gui_mch_set_text_area_pos"); +} + + void +gui_mch_enable_scrollbar(scrollbar_T *sb, int flag) +{ + /* done by default */ + /* TODO: disable scrollbar when it's too small */ +} + + void +gui_mch_set_scrollbar_thumb(scrollbar_T *sb, long val, long size, long max) +{ + ULONG total = max; + ULONG visible = size; + ULONG top = val; + ULONG hidden; + ULONG overlap = 0; + UWORD body, pot; + +kprintf("__set_scrollbar_thumb val %d size %d max %d\n", val, size, max); + + if (total > visible) + hidden = total - visible; + else + hidden = 0; + + if (top > hidden) + top = hidden; + + body = (hidden > 0) ? + (UWORD)(((ULONG)(visible - overlap) * MAXBODY) / (total - overlap)) : + MAXBODY; + + pot = (hidden > 0) ? (UWORD)(((ULONG) top * MAXPOT) / hidden) : 0; + +kprintf("__pot %x body %x\n", pot, body); + + NewModifyProp(&propGadget, gui.window, NULL, + Gadget2SInfo.Flags, + MAXPOT, pot, + MAXBODY, body, + 1); + return; + +} + + void +gui_mch_set_scrollbar_pos(scrollbar_T *sb, int x, int y, int w, int h) +{ + D("gui_mch_set_scrollbar_pos"); + /*NewModifyProp(&propGadget, gui.window, NULL, MAXPOT, MAXPOT/sb->max*y, MAXPOT, MAXBODY/sb->max/sb->size, 1);*/ +} + + void +gui_mch_create_scrollbar(scrollbar_T *sb, int orient) +{ + /* this is done by default */ +} + +#if defined(FEAT_WINDOWS) || defined(PROTO) + void +gui_mch_destroy_scrollbar(scrollbar_T *sb) +{ + /* this is done by default */ +} +#endif + +int gui_mch_init_font(char_u *font_name, int fontset) +{ + /*D("gui_mch_init_font");*/ + + gui.char_width = characterWidth; + gui.char_height = characterHeight; + gui.char_ascent = gui.window->RPort->TxBaseline; + + return OK; +} + + int +gui_mch_adjust_charsize() +{ + return FAIL; +} + + GuiFont +gui_mch_get_font( char_u *name, int giveErrorIfMissing) +{ + /*D("gui_mch_get_font");*/ + return NULL; +} + + void +gui_mch_set_font(GuiFont font) +{ + /*D("gui_mch_set_font");*/ +} + +#if 0 /* not used */ + int +gui_mch_same_font(GuiFont f1, GuiFont f2) +{ + D("gui_mch_same_font"); +} +#endif + + void +gui_mch_free_font(GuiFont font) +{ + if (font) + D("gui_mch_free_font"); +} + +#define RGB(a, b, c) ((a && 0xff) * 0x10000 + (b * 0xff) * 0x100 + (c & 0xff)) + +/* + * Get color handle for color "name". + * Return INVALCOLOR when not possible. + */ + + typedef struct guicolor_tTable + { + char *name; + unsigned long color; + UBYTE red; + UBYTE green; + UBYTE blue; + } guicolor_tTable; + + static guicolor_tTable table[] = + { + {"Grey", 0, 190,190,190}, + {"Black", 1, 0, 0, 0}, + {"DarkBlue", 2, 0, 0, 139}, + {"DarkGreen", 3, 0, 100, 0}, + {"DarkCyan", 4, 0, 139, 139}, + {"DarkRed", 5, 139, 0, 0}, + {"DarkMagenta", 6, 139, 0, 139}, + {"Brown", 7, 165, 42, 42}, + {"Gray", 8, 190, 190, 190}, + {"Grey", 9, 190, 190, 190}, + {"LightGray", 10, 211, 211, 211}, + {"LightGrey", 11, 211, 211, 211}, + {"DarkGray", 12, 169, 169, 169}, + {"DarkGrey", 13, 169, 169, 169}, + {"Blue", 14, 0, 0, 255}, + {"LightBlue", 15, 173, 216, 230}, + {"Green", 16, 0, 255, 0}, + {"LightGreen", 17, 144, 238, 144}, + {"Cyan", 18, 0, 255, 255}, + {"LightCyan", 19, 224, 255, 255}, + {"Red", 20, 255, 0, 0}, + {"LightRed", 21, 255, 0, 0}, /*?*/ + {"Magenta", 22, 255, 0, 255}, + {"LightMagenta",23, 255, 0, 255}, /*?*/ + {"Yellow", 24, 255, 255, 0}, + {"LightYellow", 25, 255, 255, 224}, /* TODO: add DarkYellow */ + {"White", 26, 255, 255, 255}, + {"SeaGreen", 27, 46, 139, 87}, + {"Orange", 28, 255, 165, 0}, + {"Purple", 30, 160, 32, 240}, + {"SlateBlue", 31, 106, 90, 205}, + {"grey90", 32, 229, 229, 229}, + {"grey95", 33, 242, 242, 242}, + {"grey80", 34, 204, 204, 204}, + {NULL, NULL}, + }; + + guicolor_T +gui_mch_get_color(char_u *name) +{ + + guicolor_T color = INVALCOLOR; + + int i; + + for (i = 0; table[i].name != NULL;i++) + { + if (stricmp(name, table[i].name) == 0) + { + //color = table[i].color; + color = i; + } + } + +#if 0 + if (color == INVALCOLOR) + { + char *looky = NULL; + + color = strtol((char*)name, &looky, 10); + if (*looky != NUL) + color = INVALCOLOR; + } +#endif + + kprintf("gui_mch_get_color[%s] = %s\n", name, table[color].name); + + return color; +} + +static UBYTE getrealcolor(guicolor_T i) +{ + if (!MyColorTable[i].alloced) + { + MyColorTable[i].pen = ObtainBestPen(gui.window->WScreen->ViewPort.ColorMap, + table[i].red * 0x01010101, + table[i].green * 0x01010101, + table[i].blue * 0x01010101, + OBP_FailIfBad, FALSE, + OBP_Precision, PRECISION_GUI, + TAG_DONE); + if (MyColorTable[i].pen != -1) + { + MyColorTable[i].alloced = TRUE; + } + } + + return MyColorTable[i].pen; +} + + + void +gui_mch_set_colors(guicolor_T fg, guicolor_T bg) +{ +#if 0 + if (fg == 0) + { + fg = 1; + } +#endif + SetABPenDrMd(gui.window->RPort, getrealcolor(fg), getrealcolor(bg), JAM2); + +kprintf("gui_mch_set_colors %s,%s\n", table[fg].name, table[bg].name); +} + + void +gui_mch_set_fg_color(guicolor_T color) +{ +#if 0 + if (color == 0) + { + color = 1; /* vim sends 0 as default color which is ALWAYS the + background on the amiga scrolling with colours as the + background is a very bad idea on slow machines*/ + } +#endif + SetAPen(gui.window->RPort, getrealcolor(color)); + SetDrMd(gui.window->RPort, JAM2); + +kprintf("gui_mch_set_fg_color %s\n", table[color].name); + +} + + void +gui_mch_set_bg_color(guicolor_T color) +{ + SetBPen(gui.window->RPort, getrealcolor(color)); +kprintf("gui_mch_set_bg_color %s\n", table[color].name); + +} + + void +gui_mch_draw_string(int row, int col, char_u *s, int len, int flags) +{ +#if 1 + char tempstring[300]; + + memcpy(tempstring, s, len); + tempstring[len] = '\0'; + + kprintf("gui_mch_draw_string(%s) flags %x\n", tempstring, flags); +#endif + + if (flags & DRAW_TRANSP) + { + SetDrMd(gui.window->RPort, JAM1); + Move(gui.window->RPort, posWidthCharToPoint(col), posHeightCharToPoint(row) + gui.window->RPort->TxBaseline); + Text(gui.window->RPort, s, len); + } + else + { + SetDrMd(gui.window->RPort, JAM2); + Move(gui.window->RPort, posWidthCharToPoint(col), posHeightCharToPoint(row) + gui.window->RPort->TxBaseline); + Text(gui.window->RPort, s, len); + } + + if (flags & DRAW_BOLD) + { + SetDrMd(gui.window->RPort, JAM1); + Move(gui.window->RPort, posWidthCharToPoint(col)+1, posHeightCharToPoint(row) + gui.window->RPort->TxBaseline); + Text(gui.window->RPort, s, len); + } + + if (flags & DRAW_UNDERL) + { + Move(gui.window->RPort, posWidthCharToPoint(col), posHeightCharToPoint(row + 1) - 1); + Draw(gui.window->RPort, posWidthCharToPoint(col+len) - 1, posHeightCharToPoint(row + 1) - 1); + } + + SetDrMd(gui.window->RPort, JAM2); +} + + int +gui_mch_haskey(char_u *name) +{ + int i; + + D("gui_mch_haskey"); + + for (i = 0; special_keys[i].vim_code1 != NUL; i++) + if (name[0] == special_keys[i].vim_code0 && + name[1] == special_keys[i].vim_code1) + return OK; + return FAIL; +} + + void +gui_mch_beep(void) +{ + D("gui_mch_beep"); +} + + void +gui_mch_flash(int msec) +{ + D("gui_mch_flash"); + + SetDrMd(gui.window->RPort, COMPLEMENT); + RectFill(gui.window->RPort, 0, 0, gui.window->GZZWidth - 1, gui.window->GZZHeight - 1); + Delay(msec * 50 / 1000); + RectFill(gui.window->RPort, 0, 0, gui.window->GZZWidth - 1, gui.window->GZZHeight - 1); + SetDrMd(gui.window->RPort, JAM2); +} + + void +gui_mch_invert_rectangle( int r, int c, int nr, int nc) +{ + printf("gui_mch_invert_rectangle %d %d %d %d\n", r, c, nr, nc); +} + + void +gui_mch_iconify(void) +{ + D("gui_mch_iconify"); +} + +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * Bring the Vim window to the foreground. + */ + void +gui_mch_set_foreground() +{ + WindowToFront(gui.window); + D("gui_mch_set_foreground"); +} +#endif + + void +gui_mch_settitle(char_u *title, char_u *icon) +{ + SetWindowTitles(gui.window, title, (STRPTR)~0); + D("gui_mch_settitle"); +} + + void +gui_mch_stop_blink(void) +{ + gui_undraw_cursor(); + D("gui_mch_stop_blink"); +} + + void +gui_mch_start_blink(void) +{ + gui_update_cursor(FALSE, FALSE); + D("gui_mch_start_blink"); +} + + void +gui_mch_draw_hollow_cursor(guicolor_T color) +{ + drawBox(DB_NotFilled, gui.col, gui.row, characterWidth, characterHeight, color); +} + + void +gui_mch_draw_part_cursor( int w, int h, guicolor_T color) +{ + D("gui_mch_part_cursor"); + drawBox(DB_Filled, gui.col, gui.row, w, h, color); +} + + void +gui_mch_update(void) +{ + checkEventHandler(); + return ; +} + + int +gui_mch_wait_for_chars(int wtime) +{ + ULONG timermask = 1L << TimerMP->mp_SigBit; + ULONG winmask = 1L << gui.window->UserPort->mp_SigBit; + int retval = FAIL; + + kprintf("========== gui_mch_wait_for_chars %d\n", wtime); + + if (wtime == -1) wtime = 1000000000; + if (wtime < 20) wtime = 20; + + SetSignal(0, timermask); + TimerIO->tr_node.io_Command = TR_ADDREQUEST; + TimerIO->tr_time.tv_secs = wtime / 1000; + TimerIO->tr_time.tv_micro = (wtime % 1000) * 1000; + SendIO(&TimerIO->tr_node); + TimerSent = TRUE; + + for(;;) + { + ULONG sigs = Wait(winmask | timermask); + + if (sigs & winmask) + { + checkEventHandler(); + if (!vim_is_input_buf_empty()) + { + retval = OK; + if (!CheckIO(&TimerIO->tr_node)) AbortIO(&TimerIO->tr_node); + WaitIO(&TimerIO->tr_node); + TimerSent = FALSE; + break; + } + } + + if (sigs & timermask) + { + struct Message *msg; + + if ((msg = GetMsg(TimerMP))) + { + ReplyMsg(msg); + TimerSent = FALSE; + retval = FAIL; + break; + } + } + } + + return retval; + +// assert(wtime != 0); +// return charEventHandler(wtime); +} + + void +gui_mch_flush(void) +{ +} + + void +gui_mch_clear_block(int row1, int col1, int row2, int col2) +{ + UBYTE apen = GetAPen(gui.window->RPort); + + SetAPen(gui.window->RPort, getrealcolor(gui.back_pixel)); + RectFill(gui.window->RPort, + posWidthCharToPoint(col1), + posHeightCharToPoint(row1), + posWidthCharToPoint(col2 + 1) - 1, + posHeightCharToPoint(row2 + 1) - 1); + SetAPen(gui.window->RPort, apen); + +} + + void +gui_mch_clear_all(void) +{ + SetRast(gui.window->RPort, GetBPen(gui.window->RPort)); + refreshBorder(); + D("gui_mch_clear_all"); +} + + void +gui_mch_delete_lines(int row, int num_lines) +{ + ScrollWindowRaster(gui.window, + 0, + characterHeight * num_lines, + posWidthCharToPoint(gui.scroll_region_left), + posHeightCharToPoint(row), + posWidthCharToPoint(gui.scroll_region_right + 1) - 1, + posHeightCharToPoint(gui.scroll_region_bot + 1) - 1); + + gui_clear_block(gui.scroll_region_bot - num_lines + 1, + gui.scroll_region_left, + gui.scroll_region_bot, + gui.scroll_region_right); + +} + + void +gui_mch_insert_lines(int row, int num_lines) +{ + ScrollWindowRaster(gui.window, + 0, + -characterHeight*num_lines, + posWidthCharToPoint(gui.scroll_region_left), + posHeightCharToPoint(row), + posWidthCharToPoint(gui.scroll_region_right + 1) - 1, + posHeightCharToPoint(gui.scroll_region_bot +1 ) - 1); + + gui_clear_block(row, gui.scroll_region_left, + row + num_lines - 1, gui.scroll_region_right); + +} + + void +gui_mch_enable_menu(int flag) +{ + D("gui_mch_enable_menu"); +} + + void +gui_mch_set_menu_pos(int x, int y, int w, int h) +{ + D("gui_mch_set_menu_pos"); +} + + void +gui_mch_destroy_menu(vimmenu_T *menu) +{ + D("gui_mch_destroy_menu"); + ClearMenuStrip(gui.window); +} + + void +gui_mch_menu_grey(vimmenu_T *menu, int grey) +{ + D("gui_mch_menu_grey"); +} + + void +gui_mch_menu_hidden(vimmenu_T *menu, int hidden) +{ + D("gui_mch_menu_hidden"); + ClearMenuStrip(gui.window); +} + + void +gui_mch_draw_menubar(void) +{ + D("gui_mch_draw_menubar"); + SetMenuStrip(gui.window, gui.menu); +} + + static void +AmigaError(const char *string) +{ + static struct IntuiText pos = { 3, 0, JAM2, 17, 5, NULL, "Cancel", NULL} ; + static struct IntuiText neg = { 3, 0, JAM2, 17, 5, NULL, "Cancel", NULL} ; + static struct IntuiText message = { 3, 0, JAM2, 17, 5, NULL, NULL, NULL} ; + static char *strptr = 0; + + if (strptr) + free(strptr); + strptr = malloc(strlen(string)+1); + + message.IText = strptr; + strcpy(strptr, string); + + AutoRequest(NULL, &message, &pos, &neg, 0, 0, 300, 300); +} + + int +clip_mch_own_selection(VimClipboard *cbd) +{ + D("clib_mch_own_selection"); + return OK; +} + + void +mch_setmouse(int on) +{ +} + +/* + * Get current y mouse coordinate in text window. + * Return -1 when unknown. + */ + int +gui_mch_get_mouse_x() +{ + return gui.window->GZZMouseX; +} + + int +gui_mch_get_mouse_y() +{ + return gui.window->GZZMouseY; +} + + void +gui_mch_setmouse(x, y) + int x; + int y; +{ + /* TODO */ +} + + void +gui_mch_show_popupmenu(vimmenu_T *menu) +{ + /* TODO */ +} + + void +clip_mch_lose_selection(VimClipboard *cbd) +{ + D("clip_mch_lose_selecction"); +} + + void +clip_mch_request_selection(VimClipboard *cbd) +{ + D("clip_mch_requst_selection"); +} + + void +clip_mch_set_selection(VimClipboard *cbd) +{ +} + + long_u +gui_mch_get_rgb(guicolor_T pixel) +{ + ULONG coltable[3], color; + + GetRGB32(gui.window->WScreen->ViewPort.ColorMap, + getrealcolor(pixel), + 1, + coltable); + + color = ((coltable[0] & 0xFF000000) >> 8) | + ((coltable[1] & 0xFF000000) >> 16) | + ((coltable[2] & 0xFF000000) >> 24); + + return color; +} + +#endif /* USE_AMIGA_GUI*/ |