From 0543a9797649b5b4a75c0da0e71b570354b36b2f Mon Sep 17 00:00:00 2001 From: Spoike Date: Tue, 12 Mar 2013 23:15:32 +0000 Subject: [PATCH] ------------------------------------------------------------------------ r4239 | acceptthis | 2013-03-08 02:41:00 +0000 (Fri, 08 Mar 2013) | 2 lines Give the text edit input focus when alt-tabbing. Display tooltips on mouseover for the various defs. You need to compile first for them to show. ------------------------------------------------------------------------ git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4235 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/qclib/qcc.h | 2 + engine/qclib/qcc_pr_comp.c | 4 +- engine/qclib/qcc_pr_lex.c | 122 +++++++++++++++++++++++++++++++ engine/qclib/qccgui.c | 146 +++++++++++++++++++++++++++++++++---- engine/qclib/qccmain.c | 16 +++- 5 files changed, 270 insertions(+), 20 deletions(-) diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index 259b3f6ab..883275c6c 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -310,6 +310,7 @@ typedef struct QCC_type_s unsigned int arraysize; pbool typedefed; char *name; + char *aname; } QCC_type_t; int typecmp(QCC_type_t *a, QCC_type_t *b); int typecmp_lax(QCC_type_t *a, QCC_type_t *b); @@ -331,6 +332,7 @@ typedef struct QCC_def_s { QCC_type_t *type; char *name; + char *comment; //ui info struct QCC_def_s *next; struct QCC_def_s *nextlocal; //provides a chain of local variables for the opt_locals_marshalling optimisation. gofs_t ofs; diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 79bea749b..0d0aad023 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -9928,10 +9928,10 @@ void QCC_PR_ParseDefs (char *classname) } while (QCC_PR_CheckToken (",")); if (type->type == ev_function) - QCC_PR_CheckToken (";"); + QCC_PR_CheckTokenComment (";", &def->comment); else { - if (!QCC_PR_CheckToken (";")) + if (!QCC_PR_CheckTokenComment (";", &def->comment)) QCC_PR_ParseWarning(WARN_UNDESIRABLECONVENTION, "Missing semicolon at end of definition"); } } diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 4a5bce227..f48fec39b 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -3008,7 +3008,121 @@ void QCC_PR_Expect (char *string) } #endif +pbool QCC_PR_CheckTokenComment(char *string, char **comment) +{ + char c; + char *start; + int nl; + char *old; + int oldlen; + pbool replace = true; + pbool nextcomment = true; + if (pr_token_type != tt_punct) + return false; + + if (STRCMP (string, pr_token)) + return false; + + if (comment) + { + // skip whitespace + nl = false; + while(nextcomment) + { + nextcomment = false; + + while ((c = *pr_file_p) && qcc_iswhite(c)) + { + if (c=='\n') //allow new lines, but only if there's whitespace before any tokens, and no double newlines. + { + if (nl) + { + QCC_PR_NewLine(false); + pr_file_p++; + break; + } + nl = true; + } + else + { + pr_file_p++; + nl = false; + } + } + if (nl) + break; + + // parse // comments + if (c=='/' && pr_file_p[1] == '/') + { + pr_file_p += 2; + while (*pr_file_p == ' ' || *pr_file_p == '\t') + pr_file_p++; + start = pr_file_p; + while (*pr_file_p && *pr_file_p != '\n') + pr_file_p++; + + if (*pr_file_p == '\n') + { + QCC_PR_NewLine(true); + pr_file_p++; + } + + old = replace?NULL:*comment; + replace = false; + oldlen = old?strlen(old)+1:0; + *comment = qccHunkAlloc(oldlen + (pr_file_p-start)+1); + if (oldlen) + { + memcpy(*comment, old, oldlen-1); + memcpy(*comment+oldlen-1, "\n", 1); + } + memcpy(*comment + oldlen, start, pr_file_p - start); + oldlen = oldlen+pr_file_p - start; + while(oldlen > 0 && ((*comment)[oldlen-1] == '\r' || (*comment)[oldlen-1] == '\n' || (*comment)[oldlen-1] == '\t' || (*comment)[oldlen-1] == ' ')) + oldlen--; + (*comment)[oldlen] = 0; + nextcomment = true; //include the next // too + nl = true; + } + // parse /* comments + else if (c=='/' && pr_file_p[1] == '*' && replace) + { + pr_file_p+=2; + start = pr_file_p; + + do + { + if (pr_file_p[0]=='\n') + QCC_PR_NewLine(true); + if (pr_file_p[1] == 0) + { + QCC_PR_ParseError(0, "EOF inside comment\n"); + pr_file_p++; + pr_file_p-=2; + break; + } + pr_file_p++; + } while (pr_file_p[0] != '*' || pr_file_p[1] != '/'); + + old = replace?NULL:*comment; + replace = false; + oldlen = old?strlen(old):0; + *comment = qccHunkAlloc(oldlen + (pr_file_p-start)+1); + memcpy(*comment, old, oldlen); + memcpy(*comment + oldlen, start, pr_file_p - start); + (*comment)[oldlen+pr_file_p - start] = 0; + + pr_file_p+=2; + } + } + } + + //and then do the rest properly. + QCC_PR_Lex (); + return true; +} /* ============= PR_Check @@ -3274,6 +3388,11 @@ char *TypeName(QCC_type_t *type) args--; strcat(ret, type->name); + if (type->aname) + { + strcat(ret, " "); + strcat(ret, type->aname); + } type = type->next; if (type || varg) @@ -3472,7 +3591,10 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype) if (STRCMP(pr_token, ",") && STRCMP(pr_token, ")")) { + newtype = true; name = QCC_PR_ParseName (); + nptype->aname = qccHunkAlloc(strlen(name)+1); + strcpy(nptype->aname, name); if (definenames) strcpy (pr_parm_names[numparms], name); } diff --git a/engine/qclib/qccgui.c b/engine/qclib/qccgui.c index 7694bfbe5..662adec92 100644 --- a/engine/qclib/qccgui.c +++ b/engine/qclib/qccgui.c @@ -280,6 +280,8 @@ typedef struct editor_s { char filename[MAX_PATH]; //abs HWND window; HWND editpane; + HWND tooltip; + char tooltiptext[1024]; pbool modified; time_t filemodifiedtime; struct editor_s *next; @@ -389,6 +391,79 @@ void EditorMenu(editor_t *editor, WPARAM wParam) } } +char *WordUnderCursor(editor_t *editor, char *buffer, int buffersize) +{ + unsigned char linebuf[1024]; + DWORD charidx; + DWORD lineidx; + POINT pos; + RECT rect; + GetCursorPos(&pos); + GetWindowRect(editor->editpane, &rect); + pos.x -= rect.left; + pos.y -= rect.top; + charidx = SendMessage(editor->editpane, EM_CHARFROMPOS, 0, (LPARAM)&pos); + lineidx = SendMessage(editor->editpane, EM_LINEFROMCHAR, charidx, 0); + charidx -= SendMessage(editor->editpane, EM_LINEINDEX, lineidx, 0); + + Edit_GetLine(editor->editpane, lineidx, linebuf, sizeof(linebuf)); + + //skip back to the start of the word + while(charidx > 0 && ( + (linebuf[charidx-1] >= 'a' && linebuf[charidx-1] <= 'z') || + (linebuf[charidx-1] >= 'A' && linebuf[charidx-1] <= 'Z') || + (linebuf[charidx-1] >= '0' && linebuf[charidx-1] <= '9') || + linebuf[charidx-1] == '_' || + linebuf[charidx-1] >= 128 + )) + { + charidx--; + } + + //copy the result out + lineidx = 0; + buffersize--; + while (buffersize && + (linebuf[charidx] >= 'a' && linebuf[charidx] <= 'z') || + (linebuf[charidx] >= 'A' && linebuf[charidx] <= 'Z') || + (linebuf[charidx] >= '0' && linebuf[charidx] <= '9') || + linebuf[charidx] == '_' || + linebuf[charidx] >= 128 + ) + { + buffer[lineidx++] = linebuf[charidx++]; + buffersize--; + } + + buffer[lineidx++] = 0; + return buffer; +} +char *GetTooltipText(editor_t *editor) +{ + char wordbuf[256]; + char *defname; + defname = WordUnderCursor(editor, wordbuf, sizeof(wordbuf)); + if (!*defname) + return NULL; + else if (globalstable.numbuckets) + { + QCC_def_t *def; + def = QCC_PR_GetDef(NULL, defname, NULL, false, 0, false); + if (def) + { + static char buffer[1024]; + //note function argument names do not persist beyond the function def. we might be able to read the function's localdefs for them, but that's unreliable/broken with builtins where they're most needed. + if (def->comment) + _snprintf(buffer, sizeof(buffer)-1, "%s %s\r\n%s", TypeName(def->type), def->name, def->comment); + else + _snprintf(buffer, sizeof(buffer)-1, "%s %s", TypeName(def->type), def->name); + return buffer; + } + return NULL; + } + else + return NULL;//"Type info not available. Compile first."; +} static LONG CALLBACK EditorWndProc(HWND hWnd,UINT message, WPARAM wParam,LPARAM lParam) { @@ -449,25 +524,27 @@ static LONG CALLBACK EditorWndProc(HWND hWnd,UINT message, goto gdefault; case WM_CREATE: editor->editpane = CreateAnEditControl(hWnd); - /* - editor->editpane=CreateWindowEx(WS_EX_CLIENTEDGE, - richedit?RICHEDIT_CLASS:"EDIT", - "", - WS_CHILD | WS_VISIBLE | - WS_HSCROLL | WS_VSCROLL | ES_LEFT | ES_WANTRETURN | - ES_MULTILINE | ES_AUTOVSCROLL, - 0, 0, 0, 0, - hWnd, - NULL, - ghInstance, - NULL); -*/ if (richedit) { SendMessage(editor->editpane, EM_EXLIMITTEXT, 0, 1<<31); - SendMessage(editor->editpane, EM_SETUNDOLIMIT, 256, 256); } + + editor->tooltip = CreateWindowEx(0, TOOLTIPS_CLASS, NULL, WS_POPUP|TTS_ALWAYSTIP|TTS_NOPREFIX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWnd, NULL, ghInstance, NULL); + if (editor->tooltip) + { + TOOLINFO toolInfo = { 0 }; + toolInfo.cbSize = sizeof(toolInfo); + toolInfo.hwnd = hWnd; + toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS | TTF_TRACK | TTF_ABSOLUTE; + toolInfo.uId = (UINT_PTR)editor->editpane; + toolInfo.lpszText = ""; + SendMessage(editor->tooltip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo); + SendMessage(editor->tooltip, TTM_SETMAXTIPWIDTH, 0, 500); + } + goto gdefault; + case WM_SETFOCUS: + SetFocus(editor->editpane); goto gdefault; case WM_SIZE: GetClientRect(hWnd, &rect); @@ -479,6 +556,38 @@ static LONG CALLBACK EditorWndProc(HWND hWnd,UINT message, EndPaint(hWnd,(LPPAINTSTRUCT)&ps); return TRUE; break; + case WM_SETCURSOR: + { + POINT pos; + char *newtext; + TOOLINFO toolInfo = { 0 }; + toolInfo.cbSize = sizeof(toolInfo); + toolInfo.hwnd = hWnd; + toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS | TTF_TRACK; + toolInfo.uId = (UINT_PTR)editor->editpane; + newtext = GetTooltipText(editor); + toolInfo.lpszText = editor->tooltiptext; + if (!newtext) + newtext = ""; + if (strcmp(editor->tooltiptext, newtext)) + { + strncpy(editor->tooltiptext, newtext, sizeof(editor->tooltiptext)-1); + SendMessage(editor->tooltip, TTM_UPDATETIPTEXT, (WPARAM)0, (LPARAM)&toolInfo); + if (*editor->tooltiptext) + SendMessage(editor->tooltip, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&toolInfo); + else + SendMessage(editor->tooltip, TTM_TRACKACTIVATE, (WPARAM)FALSE, (LPARAM)&toolInfo); + } + + GetCursorPos(&pos); + if (pos.x >= 60) + pos.x -= 60; + else + pos.x = 0; + pos.y += 30; + SendMessage(editor->tooltip, TTM_TRACKPOSITION, (WPARAM)0, MAKELONG(pos.x, pos.y)); + } + goto gdefault; case WM_COMMAND: if (HIWORD(wParam) == EN_CHANGE && (HWND)lParam == editor->editpane) { @@ -1044,6 +1153,8 @@ void EditFile(char *name, int line) int EditorSave(editor_t *edit) { + DWORD selstart; + char title[2048]; struct stat sbuf; int len; char *file; @@ -1067,6 +1178,11 @@ int EditorSave(editor_t *edit) stat(edit->filename, &sbuf); edit->filemodifiedtime = sbuf.st_mtime; + //remove the * in a silly way. + SendMessage(edit->editpane, EM_GETSEL, (WPARAM)&selstart, (LPARAM)0); + sprintf(title, "%s:%i - FTEQCC Editor", edit->filename, 1+Edit_LineFromChar(edit->editpane, selstart)); + SetWindowText(edit->window, title); + return true; } void EditorsRun(void) @@ -1650,7 +1766,7 @@ static LONG CALLBACK MainWndProc(HWND hWnd,UINT message, 0, 0, 320, 200, hWnd, (HMENU) 0xCAC, ghInstance, (LPSTR) NULL); ShowWindow(gotodefbox, SW_SHOW); - gotodefaccept = CreateWindowEx(WS_EX_CLIENTEDGE, "BUTTON", "GO", + gotodefaccept = CreateWindowEx(WS_EX_CLIENTEDGE, "BUTTON", "Def", WS_CHILD | WS_CLIPCHILDREN | BS_DEFPUSHBUTTON, 0, 0, 320, 200, hWnd, (HMENU) 0x4404, ghInstance, (LPSTR) NULL); ShowWindow(gotodefaccept, SW_SHOW); diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index bafc3e0d0..69e93c7a3 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -3419,9 +3419,19 @@ void QCC_ContinueCompile(void) QCC_FinishCompile(); PostCompile(); - if (!PreCompile()) - return; - QCC_main(myargc, myargv); + + if (currentsourcefile < numsourcefiles) + { + if (!PreCompile()) + return; + QCC_main(myargc, myargv); + } + else + { + qcc_compileactive = false; + numsourcefiles = 0; + currentsourcefile = 0; + } return; } s = qcc_token;