New form scope bug fixing.

This commit is contained in:
Scott Duensing 2026-04-03 19:29:09 -05:00
parent bf5bf9bb1d
commit e36d4b9cec
8 changed files with 97 additions and 39 deletions

View file

@ -1993,8 +1993,10 @@ static void parseBeginForm(BasParserT *p) {
basSymTabEnterFormScope(&p->sym, formName);
// Emit a forward JMP that will skip form init code (patched at ENDFORM).
// If no init code is emitted, the JMP is patched to jump to right here (noop).
// Emit a forward JMP to skip over form init code. All module-level
// bytecode inside the form scope (array DIMs, UDT init, executable
// statements, JMPs over SUB bodies) goes into the init block that
// runs at form load time, not at program startup.
basEmit8(&p->cg, OP_JMP);
p->formInitJmpAddr = basCodePos(&p->cg);
basEmit16(&p->cg, 0); // placeholder — patched at ENDFORM
@ -2017,24 +2019,14 @@ static void parseEndForm(BasParserT *p) {
int32_t varCount = basSymTabLeaveFormScope(&p->sym);
// Determine if any form init code was emitted
int32_t initStart = p->formInitCodeStart;
int32_t initAddr = -1;
int32_t initLen = 0;
int32_t curPos = basCodePos(&p->cg);
// Close the form init block: add OP_RET and patch the JMP
basEmit8(&p->cg, OP_RET);
int32_t initAddr = p->formInitCodeStart;
int32_t initLen = basCodePos(&p->cg) - p->formInitCodeStart;
if (curPos > initStart) {
// Init code was emitted — add OP_RET to end the init block
basEmit8(&p->cg, OP_RET);
initAddr = initStart;
initLen = basCodePos(&p->cg) - initStart;
}
// Patch the JMP to skip over init code (land here)
if (p->formInitJmpAddr >= 0) {
int16_t offset = (int16_t)(basCodePos(&p->cg) - (p->formInitJmpAddr + 2));
basPatch16(&p->cg, p->formInitJmpAddr, offset);
}
// Patch the JMP to skip over the entire init block
int16_t offset = (int16_t)(basCodePos(&p->cg) - (p->formInitJmpAddr + 2));
basPatch16(&p->cg, p->formInitJmpAddr, offset);
p->formInitJmpAddr = -1;
p->formInitCodeStart = -1;

View file

@ -552,8 +552,7 @@ void basFormRtHideForm(void *ctx, void *formRef) {
return;
}
form->window->visible = false;
dvxInvalidateWindow(rt->ctx, form->window);
dvxHideWindow(rt->ctx, form->window);
}
@ -724,8 +723,18 @@ BasFormT *basFormRtLoadFrm(BasFormRtT *rt, const char *source, int32_t sourceLen
continue;
}
// "VERSION x.xx" -- skip version declaration
// "VERSION DVX x.xx" (native) or "VERSION x.xx" (VB import)
if (strncasecmp(trimmed, "VERSION ", 8) == 0) {
const char *ver = trimmed + 8;
if (strncasecmp(ver, "DVX ", 4) != 0) {
double vbVer = atof(ver);
if (vbVer > 2.0) {
return NULL; // VB4+ form, not compatible
}
}
continue;
}
@ -1076,7 +1085,7 @@ void basFormRtShowForm(void *ctx, void *formRef, bool modal) {
return;
}
form->window->visible = true;
dvxShowWindow(rt->ctx, form->window);
dvxRaiseWindow(rt->ctx, form->window);
if (form->frmAutoSize) {

View file

@ -401,6 +401,22 @@ bool dsgnLoadFrm(DsgnStateT *ds, const char *source, int32_t sourceLen) {
}
if (strncasecmp(trimmed, "VERSION ", 8) == 0) {
// Accept "VERSION DVX x.xx" (native) and "VERSION x.xx" (VB import).
// Reject VB forms with version > 1.xx (VB4+/VB6 use features we
// don't support like OLE controls and binary properties).
const char *ver = trimmed + 8;
if (strncasecmp(ver, "DVX ", 4) == 0) {
// Native DVX BASIC form — always accepted
} else {
// VB form — check version number
double vbVer = atof(ver);
if (vbVer > 2.0) {
return false; // VB4+ form, not compatible
}
}
continue;
}
@ -1014,7 +1030,7 @@ int32_t dsgnSaveFrm(const DsgnStateT *ds, char *buf, int32_t bufSize) {
int32_t pos = 0;
pos += snprintf(buf + pos, bufSize - pos, "VERSION 1.00\n");
pos += snprintf(buf + pos, bufSize - pos, "VERSION DVX 1.00\n");
pos += snprintf(buf + pos, bufSize - pos, "Begin Form %s\n", ds->form->name);
pos += snprintf(buf + pos, bufSize - pos, " Caption = \"%s\"\n", ds->form->caption);
pos += snprintf(buf + pos, bufSize - pos, " Layout = %s\n", ds->form->layout);

View file

@ -902,9 +902,8 @@ static void compileAndRun(void) {
clearOutput();
setStatus("Compiling...");
// Force a display update so the status is visible
dvxInvalidateWindow(sAc, sWin);
dvxSetBusy(sAc, true);
dvxUpdate(sAc);
// Build source: either concatenate project files or use editor contents
char *concatBuf = NULL;
@ -921,6 +920,7 @@ static void compileAndRun(void) {
if (!concatBuf) {
setStatus("Out of memory.");
dvxSetBusy(sAc, false);
return;
}
@ -1076,6 +1076,8 @@ static void compileAndRun(void) {
arrput(sProject.sourceMap, mapEntry);
sProject.sourceMapCount = (int32_t)arrlen(sProject.sourceMap);
}
dvxUpdate(sAc);
}
concatBuf[pos] = '\0';
@ -1099,6 +1101,7 @@ static void compileAndRun(void) {
if (!parser) {
free(concatBuf);
setStatus("Out of memory.");
dvxSetBusy(sAc, false);
return;
}
@ -1125,6 +1128,7 @@ static void compileAndRun(void) {
}
setStatus("Compilation failed.");
dvxSetBusy(sAc, false);
basParserFree(parser);
free(parser);
free(concatBuf);
@ -1139,9 +1143,12 @@ static void compileAndRun(void) {
if (!mod) {
setStatus("Failed to build module.");
dvxSetBusy(sAc, false);
return;
}
dvxSetBusy(sAc, false);
// Cache the compiled module for Ctrl+F5
if (sCachedModule) {
basModuleFree(sCachedModule);
@ -1187,11 +1194,11 @@ static void runModule(BasModuleT *mod) {
bool hadCodeWin = sCodeWin && sCodeWin->visible;
bool hadPrjWin = sProjectWin && sProjectWin->visible;
if (sFormWin) { sFormWin->visible = false; dvxInvalidateWindow(sAc, sFormWin); }
if (sToolboxWin) { sToolboxWin->visible = false; dvxInvalidateWindow(sAc, sToolboxWin); }
if (sPropsWin) { sPropsWin->visible = false; dvxInvalidateWindow(sAc, sPropsWin); }
if (sCodeWin) { sCodeWin->visible = false; dvxInvalidateWindow(sAc, sCodeWin); }
if (sProjectWin) { sProjectWin->visible = false; dvxInvalidateWindow(sAc, sProjectWin); }
if (sFormWin) { dvxHideWindow(sAc, sFormWin); }
if (sToolboxWin) { dvxHideWindow(sAc, sToolboxWin); }
if (sPropsWin) { dvxHideWindow(sAc, sPropsWin); }
if (sCodeWin) { dvxHideWindow(sAc, sCodeWin); }
if (sProjectWin) { dvxHideWindow(sAc, sProjectWin); }
// Create VM
BasVmT *vm = basVmCreate();
@ -1291,11 +1298,11 @@ static void runModule(BasModuleT *mod) {
basVmDestroy(vm);
// Restore IDE windows
if (hadFormWin && sFormWin) { sFormWin->visible = true; dvxInvalidateWindow(sAc, sFormWin); }
if (hadToolbox && sToolboxWin) { sToolboxWin->visible = true; dvxInvalidateWindow(sAc, sToolboxWin); }
if (hadProps && sPropsWin) { sPropsWin->visible = true; dvxInvalidateWindow(sAc, sPropsWin); }
if (hadCodeWin && sCodeWin) { sCodeWin->visible = true; dvxInvalidateWindow(sAc, sCodeWin); }
if (hadPrjWin && sProjectWin) { sProjectWin->visible = true; dvxInvalidateWindow(sAc, sProjectWin); }
if (hadFormWin && sFormWin) { dvxShowWindow(sAc, sFormWin); }
if (hadToolbox && sToolboxWin) { dvxShowWindow(sAc, sToolboxWin); }
if (hadProps && sPropsWin) { dvxShowWindow(sAc, sPropsWin); }
if (hadCodeWin && sCodeWin) { dvxShowWindow(sAc, sCodeWin); }
if (hadPrjWin && sProjectWin) { dvxShowWindow(sAc, sProjectWin); }
// Repaint to clear destroyed runtime forms and restore designer
dvxUpdate(sAc);

View file

@ -87,7 +87,7 @@ static void onTreeReorder(WidgetT *w);
// ============================================================
static void onPrpClose(WindowT *win) {
win->visible = false;
dvxHideWindow(sPrpCtx, win);
}

View file

@ -68,7 +68,7 @@ static void onToolClick(WidgetT *w) {
static void onTbxClose(WindowT *win) {
win->visible = false;
dvxHideWindow(sDs->ctx, win);
}

View file

@ -3925,6 +3925,34 @@ WindowT *dvxCreateWindowCentered(AppContextT *ctx, const char *title, int32_t w,
}
// ============================================================
// dvxHideWindow
// ============================================================
void dvxHideWindow(AppContextT *ctx, WindowT *win) {
if (!win || !win->visible) {
return;
}
dirtyListAdd(&ctx->dirty, win->x, win->y, win->w, win->h);
win->visible = false;
}
// ============================================================
// dvxShowWindow
// ============================================================
void dvxShowWindow(AppContextT *ctx, WindowT *win) {
if (!win || win->visible) {
return;
}
win->visible = true;
dvxInvalidateWindow(ctx, win);
}
// ============================================================
// dvxDestroyWindow
// ============================================================

View file

@ -223,6 +223,12 @@ void dvxInvalidateRect(AppContextT *ctx, WindowT *win, int32_t x, int32_t y, int
// Mark the entire window content area as dirty.
void dvxInvalidateWindow(AppContextT *ctx, WindowT *win);
// Hide a window without destroying it (marks exposed region dirty).
void dvxHideWindow(AppContextT *ctx, WindowT *win);
// Show a previously hidden window (marks region dirty for repaint).
void dvxShowWindow(AppContextT *ctx, WindowT *win);
// Minimize a window (show as icon at bottom of screen)
void dvxMinimizeWindow(AppContextT *ctx, WindowT *win);