zlaunchinfo loadzlinfofromsvector(stringvector info) { zlaunchinfo zli; stringnode* cur; char token[256]; int pos = 0; initzlinfo(&zli); for (cur = info.first; cur != NULL; cur = cur->next) { /* Get the first token on this line, space seperated */ pos = 0; tokenadvance(token, cur->s, &pos); if (str_equ(token, "action", STREQU_UNCASE) || str_equ(token, "optional", STREQU_UNCASE)) { zlaunchaction* action = (zlaunchaction*) malloc(sizeof(zlaunchaction)); initaction(action); /* set optional flag if it is an optional command */ if (str_equ(token, "optional", STREQU_UNCASE)) action->optional = 1; /* get the action's title */ if (tokenadvance(token, cur->s, &pos)) action->name = str_dup(token); /* get the action's type */ if (tokenadvance(token, cur->s, &pos)) { if (str_equ(token, "run", STREQU_UNCASE)) action->type = ZL_RUN; else if (str_equ(token, "keystrokes", STREQU_UNCASE)) action->type = ZL_KEYSTROKES; else if (str_equ(token, "copy", STREQU_UNCASE)) action->type = ZL_COPY; else if (str_equ(token, "displace", STREQU_UNCASE)) action->type = ZL_DISPLACE; else if (str_equ(token, "permcopy", STREQU_UNCASE)) action->type = ZL_PERMCOPY; else if (str_equ(token, "permcopyover", STREQU_UNCASE)) action->type = ZL_PERMCOPYOVER; } /* get the action's command */ while (cur->s[pos] == ' ') pos++; action->command = str_dup(cur->s + pos); /* Add the action to the list */ addaction(&zli, action); } else if (str_equ(token, "perform", STREQU_UNCASE)) { while (tokenadvance(token, cur->s, &pos)) pushstring(&(zli.actionstoperform), str_dup(token)); } } return zli; }
void performkeystrokes(char* keystrokes) { int i; for (i = 0; i < strlen(keystrokes); i++) { if (keystrokes[i] == '<') { if (str_equ(keystrokes + i + 1, "enter", STREQU_FRONT | STREQU_UNCASE)) stuffkbdbuffer(0, '\x0D'); if (str_equ(keystrokes + i + 1, "esc", STREQU_FRONT | STREQU_UNCASE)) stuffkbdbuffer(0x01, '\x1B'); if (str_equ(keystrokes + i + 1, "left", STREQU_FRONT | STREQU_UNCASE)) stuffkbdbuffer(0x4B, 0); /* Advance to closing bracket */ while (keystrokes[i] != '>' && keystrokes[i] != '\x0') i++; } else { stuffkbdbuffer(0, keystrokes[i]); } } }
const void *assets_get(const char *url, int *size) { int i; if (str_startswith(url, "asset://")) url += 8; // Skip asset:// for (i = 0; ASSETS[i].path; i++) { if (str_equ(ASSETS[i].path, url)) { if (size) *size = ASSETS[i].size; return ASSETS[i].data; } } return NULL; }
static long get_arg_value(arg_t arg, const arg_t *args) { const arg_t *argp; if (args) { for (argp = args; argp->name; argp++) { if (strcmp(argp->name, arg.name) == 0) return argp->value; } } // Default values for some types. if (arg.type == TYPE_GOXEL) return (intptr_t)goxel(); if (arg.type == TYPE_IMAGE) return (intptr_t)goxel()->image; if (arg.type == TYPE_LAYER) return (intptr_t)goxel()->image->active_layer; if (arg.type == TYPE_BOX) return (intptr_t)&goxel()->selection; if (str_equ(arg.name, "width")) return (int)goxel()->image->export_width; if (str_equ(arg.name, "height")) return (int)goxel()->image->export_height; return 0; }
/** * @relates texteditor * @brief Prompt the user for an ASCII character to insert. If the current line * begins with a #char command, modify the argument to #char instead. **/ void texteditInsertASCII(texteditor * editor) { static int selChar; /* TODO: static isn't the way to go, or is it? */ int choice; editor->updateflags |= TUD_EDITAREA; /* TODO: let #char be anywhere on the line */ if (str_equ(editor->curline->s, "#char", STREQU_UNCASE | STREQU_RFRONT)) { /* Change character number for a #char command */ char * number; /* append decimal value for ascii char */ sscanf(editor->curline->s + 5, "%d", &selChar); choice = charselect(editor->d, selChar); if (choice == -1) return; editor->curline->s[5] = ' '; editor->curline->s[6] = '\x0'; /* change the character to a string */ number = str_duplen("", 64); sprintf(number, "%d", choice); strcat(editor->curline->s, number); free(number); texteditValidatePosition(editor); editor->updateflags |= TUD_EDITAREA; } else { /* insert ascii char */ choice = charselect(editor->d, selChar); if (choice == -1) return; texteditInsertCharacter(editor, choice); } /* Remember the choice for future reference */ selChar = choice; }
void zlaunchact(zlaunchinfo* zli) { zlaunchaction* curaction = zli->actions; stringvector successfulcopies; zlaunchcleanup(zli); successfulcopies = filetosvector(ZL_RMFILENAME, 0, 0); while (curaction != NULL) { int cmsize = strlen(curaction->command); int i = 0, j = 0; char* command; /* prevent options not in the perform list from running */ if (curaction->optional) { int perform = 0; for (svmovetofirst(&(zli->actionstoperform)); zli->actionstoperform.cur != NULL; zli->actionstoperform.cur = zli->actionstoperform.cur->next) { if (str_equ(zli->actionstoperform.cur->s, curaction->name, STREQU_UNCASE)) perform = 1; } svmovetofirst(&(zli->actionstoperform)); if (!perform) { curaction = curaction->next; continue; } } /* parse the command for %1, %2 etc */ command = str_dupmin("", cmsize); while (i < strlen(curaction->command) && j < cmsize) { switch (curaction->command[i]) { case '%': { int pos = curaction->command[++i] - 0x31; svmovetofirst(&(zli->paramlist)); if (svmoveby(&(zli->paramlist), pos) == pos) { /* Grow the command to hold the param */ char* oldcm = command; cmsize += strlen(zli->paramlist.cur->s); command = str_dupmin(command, cmsize); free(oldcm); strcat(command, zli->paramlist.cur->s); j += strlen(zli->paramlist.cur->s); } i++; } default: command[j++] = curaction->command[i++]; } } command[j] = '\x0'; switch (curaction->type) { case ZL_RUN: /* TODO: seperate args from command and pass seperately */ run(zli->bindir, command, ""); break; case ZL_KEYSTROKES: performkeystrokes(command); break; case ZL_COPY: copyfilepatternbydir(zli->datadir, ".", command, COPY_NOOVERWRITE, &successfulcopies); /* Backup list of copied files */ svectortofile(&successfulcopies, ZL_RMFILENAME); break; case ZL_DISPLACE: copyfilepatternbydir(zli->datadir, ".", command, COPY_DISPLACE, &successfulcopies); /* Backup list of copied files */ svectortofile(&successfulcopies, ZL_RMFILENAME); break; case ZL_PERMCOPY: copyfilepatternbydir(zli->datadir, ".", command, COPY_NOOVERWRITE, NULL); break; case ZL_PERMCOPYOVER: copyfilepatternbydir(zli->datadir, ".", command, COPY_OVERWRITE, NULL); break; } /* Advance and take another spin */ curaction = curaction->next; free(command); } /* Clear out the successfulcopies list */ deletestringvector(&successfulcopies); }
void testMusic(stringvector* sv, int slur, int editwidth, int flags, displaymethod* d) { int done; #ifdef SDL SDL_AudioSpec spec; /* IF opening the audio device fails, return now before we crash something. */ if (OpenSynth(&spec)) return; #endif done = 0; /* Loop through the stringvector looking for #play statements */ while (sv->cur != NULL && !done) { char* tune = strstr(sv->cur->s, "#"); if (tune != NULL && str_equ(tune, "#play ", STREQU_UNCASE | STREQU_RFRONT)) { /* Current note and settings */ musicalNote note = zzmGetDefaultNote(); musicSettings settings = zzmGetDefaultSettings(); #ifdef DOS int xoff = tune - sv->cur->s; #endif tune += 6; /* Advance to notes! */ /* Change the slur setting */ note.slur = slur; /* Update everything because we have likely shifted to a new line. */ updateditbox(d, sv, U_EDITAREA, editwidth, flags, "", 1); while (note.src_pos < strlen(tune) && !done) { #ifdef DOS int oldpos = note.src_pos; char* strpart; #endif if (d->getkey() != DKEY_NONE) done = 1; note = zzmGetNote(tune, note); #ifdef DOS /* In DOS, display everything as we go along */ /* Display the whole line */ updateditbox(d, sv, U_CENTER, editwidth, flags, "", 1); /* Display the part of the string which will be played now */ strpart = str_duplen(tune + oldpos, note.src_pos - oldpos); d->print(oldpos + 15 + xoff, 13, ZOC_MPLAY_COLOUR, strpart); free(strpart); d->cursorgo(oldpos + 15 + xoff, 13); pcSpeakerPlayNote(note, settings); #elif defined SDL SynthPlayNote(spec, note, settings); #endif } } sv->cur = sv->cur->next; } #ifdef SDL /* TODO: instead of just sitting here, display the progress of playback */ /* Wait until the music is done or the user presses a key */ while (!IsSynthBufferEmpty() && d->getkey() == DKEY_NONE) ; CloseSynth(); #elif defined DOS pcSpeakerFinish(); #endif }
int editbox(char *title, stringvector * sv, int editwidth, int flags, displaymethod * d) { int key; /* the key */ int i, j; /* general counters */ int done = 0; /* true when editing/viewing is done */ int updateflags; /* flags to determine what needs update */ stringnode *centerstr; /* str in center of dialog */ stringnode *loopstr; /* node pointer for use in looping */ int selChar = 0; /* vars only relating to editing */ int pos = 0; /* position in sv->cur->s */ char *tmpstr; /* temporary string for pushing */ char strbuf[80] = ""; /* general buffer */ static char savefilename[SAVEFILENAME_LEN] = "temp.zoc"; /* selection variables */ int selectFlag = 0; /* Status of the shift key */ int selPos = -1; /* Position of cursor when selection started; -1 when no selection */ int selLineOffset = 0; /* Offset of line where selection started; positive when below centerstr, negative when above */ /* statics */ static int insertflag = 1; /* nonzero when in insert mode */ static int wrapwidth = 42; /* where to wrap */ /* if there is no string, add one */ if (sv->cur == NULL || sv->first == NULL || sv->last == NULL) pushstring(sv, strcpy((char *) malloc(editwidth + 2), "")); if (sv->cur == NULL) return 0; centerstr = sv->cur; if (editwidth == EDITBOX_NOEDIT) { d->cursorgo(9, 13); /* Look for @title on first line */ if ((flags & EDITBOX_ZOCMODE) && sv->first != NULL && sv->first->s[0] == '@') { /* Display the first line as the title, not in the box itself */ if (sv->first->s[1] != '\x0') title = sv->first->s + 1; /* What's the harm? We're only looking. */ if (centerstr == sv->first) centerstr = centerstr->next; } } /* Check for NULL after advancing past @title, if we did so */ if (centerstr == NULL) return 0; drawscrollbox(d, 0, 0, 1); updateflags = U_ALL; while (!done) { if (editwidth) d->cursorgo(9 + pos, 13); /* If in select mode, center line should be updated no matter what */ if (selPos != -1) updateflags |= U_CENTER; if (updateflags & U_PANEL && editwidth) draweditpanel(insertflag, wrapwidth, flags & EDITBOX_ZOCMODE, d); sv->cur = centerstr; updateditbox(d, sv, updateflags, editwidth, flags, title, selPos == -1); updateflags = U_NONE; /* Draw highlighted text if applicable */ if (selPos != -1) { int startPos = 0, endPos = 0; if (selLineOffset > 0) { startPos = pos; endPos = strlen(centerstr->s); } else if (selLineOffset < 0) { startPos = 0; endPos = pos; } else { if (selPos > pos) { startPos = pos; endPos = selPos; } else { startPos = selPos; endPos = pos; } } for (j = startPos; j < endPos; j++) d->putch(9 + j, 13, centerstr->s[j], ZOC_HIGHLIGHT_COLOUR); if (selLineOffset != 0) { /* Draw meat lines */ if (selLineOffset > 0) { for (i = 1, loopstr = centerstr->next; i < selLineOffset && i < 8 && loopstr != NULL; i++, loopstr = loopstr->next) d->print_discrete(9, 13 + i, ZOC_HIGHLIGHT_COLOUR, loopstr->s); } else { for (i = -1, loopstr = centerstr->prev; i > selLineOffset && i > -8 && loopstr != NULL; i--, loopstr = loopstr->prev) d->print_discrete(9, 13 + i, ZOC_HIGHLIGHT_COLOUR, loopstr->s); } /* Draw farthest line from centerstr */ if (i < 8 && i > -8 && loopstr != NULL) { if (selLineOffset < 0) { startPos = selPos; endPos = strlen(loopstr->s); } else if (selLineOffset > 0) { startPos = 0; endPos = selPos; } for (j = startPos; j < endPos; j++) d->putch_discrete(9 + j, 13 + i, loopstr->s[j], ZOC_HIGHLIGHT_COLOUR); } } /* Update the display */ d->update(3, 4, 51, 19); } /* Get the key */ key = d->getch(); selectFlag = d->shift(); /* If we just started selecting, remember where we started */ if (selectFlag && selPos == -1) selPos = pos; /* Keys which work when editing and browsing */ switch (key) { case DKEY_UP: /* Up Arrow */ if (centerstr->prev != NULL && !(!editwidth && centerstr->prev == sv->first && sv->first->s[0] == '@')) { centerstr = centerstr->prev; if (pos > strlen(centerstr->s)) pos = strlen(centerstr->s); if (selectFlag) selLineOffset++; updateflags = U_EDITAREA; } break; case DKEY_DOWN: /* Down Arrow */ if (centerstr->next != NULL) { centerstr = centerstr->next; if (pos > strlen(centerstr->s)) pos = strlen(centerstr->s); if (selectFlag) selLineOffset--; updateflags = U_EDITAREA; } break; case DKEY_PAGEUP: /* Page Up */ for (i = 0; i < 7 && centerstr->prev != NULL && !(!editwidth && centerstr->prev == sv->first && sv->first->s[0] == '@'); i++) { centerstr = centerstr->prev; if (selectFlag) selLineOffset++; } if (pos > strlen(centerstr->s)) pos = strlen(centerstr->s); updateflags = U_EDITAREA; break; case DKEY_PAGEDOWN: /* Page Down */ for (i = 0; i < 7 && centerstr->next != NULL; i++) { centerstr = centerstr->next; if (selectFlag) selLineOffset--; } if (pos > strlen(centerstr->s)) pos = strlen(centerstr->s); updateflags = U_EDITAREA; break; case DKEY_CTRL_C: case DKEY_CTRL_X: /* Copy to register */ if (selPos != -1) { stringnode *selStart = centerstr, *selEnd = centerstr; int selStartPos, selEndPos; selectionBounds bounds; if (selLineOffset > 0) { /* Other end of selection is below current line, move end down to meet it. */ selStartPos = pos; selEndPos = selPos; for (i = 0; i < selLineOffset; i++) if (selEnd->next != NULL) selEnd = selEnd->next; } else if (selLineOffset < 0) { /* Other end of selection is above current line, move end up to meet it. */ selStartPos = selPos; selEndPos = pos; for (i = 0; i > selLineOffset; i--) if (selStart->prev != NULL) selStart = selStart->prev; } else { /* Selection is only on current line: selStartPos gets the lesser of selPos & pos */ if (selPos > pos) { selStartPos = pos; selEndPos = selPos; } else { selStartPos = selPos; selEndPos = pos; } } bounds.startLine = selStart; bounds.endLine = selEnd; bounds.startPos = selStartPos; bounds.endPos = selEndPos; regyank('\"', bounds); } break; case DKEY_ESC: if (editwidth > EDITBOX_NOEDIT) done = EDITBOX_OK; else done = EDITBOX_CANCEL; break; } /* Keys pertaining to browsing only */ if (editwidth == EDITBOX_NOEDIT) { switch (key) { case DKEY_ENTER: done = EDITBOX_OK; break; } /* If movement is enabled... */ if (flags & EDITBOX_MOVEMENT) { switch (key) { case DKEY_BACKSPACE: done = EDITBOX_BACK; break; case DKEY_RIGHT: done = EDITBOX_FORWARD; break; case DKEY_LEFT: done = EDITBOX_BACKWARD; break; case DKEY_F1: done = EDITBOX_HELP; break; } } } /* Keys pertaining to editing only */ if (editwidth > EDITBOX_NOEDIT) { /* We are edititing! Yea! Fun time! */ switch (key) { case DKEY_NONE: break; /********** Movement ***********/ case DKEY_LEFT: /* Left Arrow */ if (pos > 0) pos--; else { /* Move to end of previous line (or current line) */ if (centerstr->prev != NULL) { centerstr = centerstr->prev; updateflags = U_EDITAREA; } pos = strlen(centerstr->s); if (selectFlag) selLineOffset++; } break; case DKEY_RIGHT: /* Right Arrow */ if (pos < strlen(centerstr->s)) pos++; else { /* Move to begining of next line (or current line) */ if (centerstr->next != NULL) { centerstr = centerstr->next; updateflags = U_EDITAREA; } pos = 0; if (selectFlag) selLineOffset--; } break; case DKEY_HOME: /* Home */ pos = 0; break; case DKEY_END: /* End */ pos = strlen(centerstr->s); break; case DKEY_UP: case DKEY_DOWN: case DKEY_PAGEUP: case DKEY_PAGEDOWN: case DKEY_CTRL_C: /* Avoid inserting these keys */ break; /********** Insert & Delete ***********/ case DKEY_INSERT: /* Insert */ insertflag = !insertflag; updateflags = U_PANEL; break; case DKEY_DELETE: /* Delete */ if (pos < strlen(centerstr->s)) { for (i = pos; i < strlen(centerstr->s); i++) centerstr->s[i] = centerstr->s[i+1]; updateflags = U_CENTER; } else if (strlen(centerstr->s) == 0 && !(sv->first == sv->last)) { /* This string is empty: destroy */ sv->cur = centerstr; deletestring(sv); centerstr = sv->cur; pos = strlen(centerstr->s); updateflags = U_EDITAREA; } else if (centerstr->next != NULL) { if (strlen(centerstr->next->s) == 0) { /* Next string is empty: destroy */ sv->cur = centerstr->next; deletestring(sv); updateflags = U_BOTTOM; } else if (strlen(centerstr->s) + 1 < wrapwidth) { /* merge lines; wordwrap */ i = strlen(centerstr->s); if (centerstr->s[i-1] != ' ' && centerstr->next->s[0] != ' ') { /* add a space at the end */ centerstr->s[i] = ' '; centerstr->s[++i] = 0; } sv->cur = centerstr->next; tmpstr = removestring(sv); sv->cur = centerstr; pos = wordwrap(sv, tmpstr, i, -1, wrapwidth, editwidth); centerstr = sv->cur; free(tmpstr); updateflags = U_CENTER | U_BOTTOM | U_TOP; } } break; /****** ZOC Mode & Wordwrap settings **********/ case DKEY_ALT_Z: /* alt-z - toggle ZOC mode */ flags ^= EDITBOX_ZOCMODE; updateflags = U_PANEL | U_EDITAREA; break; case DKEY_ALT_MINUS: /* alt - */ if (wrapwidth > 10) wrapwidth--; else wrapwidth = editwidth; updateflags = U_PANEL; break; case DKEY_ALT_PLUS: /* alt + */ if (wrapwidth < editwidth) wrapwidth++; else wrapwidth = 10; updateflags = U_PANEL; break; /****** Help dialog ******/ case DKEY_F1: /* F1: help dialog */ /* Look for #command on current line for lookup in help */ i = pos; while (i > 0 && centerstr->s[i] != '#') i--; if (centerstr->s[i] == '#') { /* Copy the command onto tmpstr */ tmpstr = str_dup(centerstr->s + i + 1); for (i = 0; tmpstr[i] != ' ' && tmpstr[i] != '\0'; i++) ; tmpstr[i] = '\0'; if (zztoopFindCommand(tmpstr) == -1) { /* If it's not a valid command, don't bother looking for it */ tmpstr[0] = '\0'; } /* Display the help file with the command as the topic */ helpsectiontopic("langref", tmpstr, d); free(tmpstr); } else { /* Display the oop help file */ helpsectiontopic("langref", NULL, d); } updateflags = U_ALL; break; /********* ZZM Testing ********************/ case DKEY_CTRL_T: case DKEY_ALT_T: sv->cur = centerstr; testMusic(sv, key == DKEY_CTRL_T, editwidth, flags, d); updateflags = U_EDITAREA; break; /********* File access operations *********/ case DKEY_ALT_O: /* alt+o: open file */ case DKEY_ALT_I: /* alt+i: insert file */ { stringvector filetypelist; char* filename = NULL; initstringvector(&filetypelist); pushstring(&filetypelist, "*.zoc"); pushstring(&filetypelist, "*.txt"); pushstring(&filetypelist, "*.hlp"); pushstring(&filetypelist, "*.zzm"); pushstring(&filetypelist, "*.*"); if (editbox("Select A File Type", &filetypelist, 0, 1, d) == 27) { updateflags = U_EDITAREA | U_TITLE; break; } if (filetypelist.cur != NULL) filename = filedialog(".", filetypelist.cur->s + 2, (key == DKEY_ALT_O ? "Open ZZT Object Code (ZOC) File" : "Insert ZZT Object Code (ZOC) File"), FTYPE_ALL, d); if (filename != NULL && strlen(filename) != 0) { stringvector newsvector; newsvector = filetosvector(filename, wrapwidth, editwidth); if (newsvector.first != NULL) { if (key == DKEY_ALT_O) { strcpy(savefilename, filename); /* erase & replace sv */ deletestringvector(sv); *sv = newsvector; centerstr = sv->first; } else { /* insert newsvector before centerstr */ sv->cur = centerstr; if (sv->cur == sv->first) { /* first node */ sv->first = newsvector.first; sv->cur->prev = newsvector.last; newsvector.last->next = sv->cur; centerstr = newsvector.first; } else if (sv->cur->prev != NULL) { /* middle/end node */ newsvector.first->prev = sv->cur->prev; sv->cur->prev->next = newsvector.first; newsvector.last->next = sv->cur; sv->cur->prev = newsvector.last; centerstr = newsvector.first; } else { /* this code should be unreachable */ deletestringvector(&newsvector); } } /* esle alt-i */ } /* fi file selected */ } /* fi not empty */ free(filename); removestringvector(&filetypelist); } /* block */ updateflags = U_EDITAREA | U_TITLE | U_PANEL; break; case DKEY_ALT_S: /* alt-s: save to file */ { char* filename; filename = filenamedialog(savefilename, "", "Save Object Code As", 1, d); if (filename != NULL) { /* Save to the file */ svectortofile(sv, filename); /* Remember the file name */ strncpy(savefilename, filename, SAVEFILENAME_LEN - 1); savefilename[SAVEFILENAME_LEN - 1] = '\x0'; free(filename); } } updateflags = U_EDITAREA | U_PANEL | U_PANEL; break; case DKEY_ALT_M: /* alt-m: load .zzm music */ { char* filename; filename = filedialog(".", "zzm", "Choose ZZT Music (ZZM) File", FTYPE_ALL, d); if (filename != NULL) { stringvector zzmv; zzmv = filetosvector(filename, 80, 80); if (zzmv.first != NULL) { stringvector song; song = zzmpullsong(&zzmv, zzmpicksong(&zzmv, d)); if (song.first != NULL) { /* copy song into sv */ sv->cur = centerstr; for (song.cur = song.first; song.cur != NULL; song.cur = song.cur->next) { tmpstr = (char*) malloc(editwidth + 2); if (flags & EDITBOX_ZOCMODE) { strcpy(tmpstr, "#play "); strncat(tmpstr, song.cur->s, editwidth - 6); } else { strncpy(tmpstr, song.cur->s, editwidth); } preinsertstring(sv, tmpstr); } deletestringvector(&song); } deletestringvector(&zzmv); } } free(filename); } updateflags = U_EDITAREA | U_TITLE | U_PANEL; break; case DKEY_CTRL_R: /* ctrl-r: rip music */ { /* This is mostly worthless just now */ stringvector ripped; sv->cur = centerstr; ripped = zzmripsong(sv, 4); scrolldialog("Ripped Music", &ripped, d); deletestringvector(&ripped); updateflags = U_ALL; } break; /******** Cut operation *********/ case DKEY_CTRL_DELETE: /* ctrl-delete: clear selected text */ case DKEY_CTRL_X: /* ctrl-x: cut selected text */ sv->cur = centerstr; /* Destroy the meat of the selection */ if (selPos != -1) { int selStartPos, selEndPos, offset = selLineOffset; if (offset < 0) { /* Other end is above centerstr */ offset = -offset; selStartPos = selPos; selEndPos = pos; /* Move back to top of selection */ for (i = 0; i < offset; i++) { if (sv->cur->prev != NULL) sv->cur = sv->cur->prev; } /* Change centerstr to reflect the top of the selection */ centerstr = sv->cur; } else { selStartPos = pos; selEndPos = selPos; } if (offset == 0) { /* Only one line to work with */ int deltaPos; /* Reverse selStartPos and selEndPos if start is bigger */ if (selStartPos > selEndPos) { int swapPos = selStartPos; selStartPos = selEndPos; selEndPos = swapPos; } /* Remove everything between selStartPos and selEndPos */ deltaPos = selEndPos - selStartPos; for (i = selEndPos; i < strlen(centerstr->s); i++) { centerstr->s[i - deltaPos] = centerstr->s[i]; } centerstr->s[i - deltaPos] = '\0'; /* Move the cursor to the starting position of the cut */ pos = selStartPos; } else { /* Multiple lines were involved */ /* Remove lines following the first line of the block */ sv->cur = centerstr->next; for (i = 0; i + 1 < offset; i++) { deletestring(sv); } /* Remove the string at the end of the cut */ sv->cur = centerstr->next; tmpstr = removestring(sv); /* Remove first selEndPos chars from end string */ for (i = 0; i < (strlen(tmpstr) - selEndPos); i++) tmpstr[i] = tmpstr[i+selEndPos]; tmpstr[i] = 0; /* Truncate the string at the start of the cut */ sv->cur = centerstr; sv->cur->s[selStartPos] = '\0'; /* Wordwrap the end string onto this one */ /* The -1 tells wordwrap to track the cursor position at * the beginning of tmpstr. Negative tracking values should * be used only by wordwrap for internal purposes, but * necessity warrents in this case. vv */ pos = wordwrap(sv, tmpstr, selStartPos, -1, wrapwidth, editwidth); centerstr = sv->cur; /* Follow cursor */ /* tmpstr is our responsability */ free(tmpstr); } updateflags = U_EDITAREA; } break; case DKEY_CTRL_V: /* ctrl-v: paste register */ sv->cur = centerstr; pos = regput('\"', sv, pos, wrapwidth, editwidth); centerstr = sv->cur; updateflags = U_EDITAREA; break; case DKEY_TAB: /* Tab */ /* determine tab amount */ j = 4 - (pos % 4); if (strlen(centerstr->s) + j < (wrapwidth?wrapwidth:editwidth)) { /* insert if there is room */ for (i = strlen(centerstr->s) + j; i > pos; i--) centerstr->s[i] = centerstr->s[i-j]; for (i = 0; i < j; i++) centerstr->s[pos++] = ' '; updateflags = U_CENTER; } else { /* no room; wordwrap */ for (i = 0; i < j; i++) strbuf[i] = ' '; strbuf[i] = 0; sv->cur = centerstr; pos = wordwrap(sv, strbuf, pos, pos, wrapwidth, editwidth); centerstr = sv->cur; updateflags = U_EDITAREA; } break; case DKEY_ENTER: /* Enter */ tmpstr = (char*) malloc(editwidth + 2); for (i = pos, j = 0; i < strlen(centerstr->s); i++, j++) tmpstr[j] = centerstr->s[i]; centerstr->s[pos] = 0; tmpstr[j] = 0; sv->cur = centerstr; insertstring(sv, tmpstr); centerstr = centerstr->next; pos = 0; updateflags = U_EDITAREA; break; case DKEY_BACKSPACE: /* Backspace */ if (pos > 0) { for (i = pos - 1; i < strlen(centerstr->s); i++) centerstr->s[i] = centerstr->s[i+1]; pos--; updateflags = U_CENTER; } else if (centerstr->prev != NULL) { if (strlen(centerstr->s) == 0) { /* remove current line & move up & to eol */ sv->cur = centerstr; centerstr = centerstr->prev; pos = strlen(centerstr->s); deletestring(sv); updateflags = U_TOP | U_CENTER; } else if (strlen(centerstr->prev->s) == 0) { /* remove previous line */ sv->cur = centerstr->prev; deletestring(sv); /* update center too, in case @ line has moved to top now */ updateflags = U_TOP | U_CENTER; } else if (strlen(centerstr->prev->s) + 1 < wrapwidth) { /* merge lines; wordwrap */ i = strlen(centerstr->prev->s); if (centerstr->prev->s[i-1] != ' ' && centerstr->s[0] != ' ') { /* add a space at the end */ centerstr->prev->s[i] = ' '; centerstr->prev->s[i + 1] = 0; } sv->cur = centerstr->prev; tmpstr = removestring(sv); sv->cur = centerstr; pos = wordwrap(sv, tmpstr, 0, 0, wrapwidth, editwidth); centerstr = sv->cur; free(tmpstr); updateflags = U_EDITAREA; } } break; case DKEY_CTRL_Y: /* ctrl-y: delete line */ pos = 0; sv->cur = centerstr; if (centerstr->next != NULL) { centerstr = centerstr->next; deletestring(sv); updateflags = U_CENTER | U_BOTTOM; } else if (centerstr->prev != NULL) { centerstr = centerstr->prev; deletestring(sv); updateflags = U_TOP | U_CENTER; } else { centerstr->s[0] = 0; updateflags = U_CENTER; } break; case DKEY_ESC: /* escape when done */ done = EDITBOX_OK; break; case DKEY_CTRL_A: /* ctrl-a: insert ascii char/decimal-value */ strcpy(strbuf, centerstr->s); updateflags = U_EDITAREA; if (str_equ(strbuf, "#char", STREQU_UNCASE | STREQU_RFRONT)) { /* append dec value for ascii char */ sscanf(strbuf + 5, "%d", &selChar); key = charselect(d, selChar); if (key == -1) break; selChar = key; centerstr->s[5] = ' '; centerstr->s[6] = 0; /* change c to a string */ sprintf(strbuf, "%d", selChar); strcat(centerstr->s, strbuf); pos = strlen(centerstr->s); updateflags = U_EDITAREA; break; } else { /* ctrl-a: insert ascii char */ key = charselect(d, selChar); if (key == -1) break; else selChar = key; } /* no break; we just changed the key & want to insert it */ default: key = key & 0xFF; /* Clear all but the first 8 bits */ /* Normal/weird char for insert/replace */ if (insertflag) { /* insert */ if (strlen(centerstr->s) < (wrapwidth?wrapwidth:editwidth)) { /* insert if there is room */ for (i = strlen(centerstr->s) + 1; i > pos; i--) centerstr->s[i] = centerstr->s[i-1]; centerstr->s[pos++] = key; updateflags |= U_CENTER; } else if (wrapwidth) { /* no room; wordwrap */ strbuf[0] = key; strbuf[1] = 0; sv->cur = centerstr; pos = wordwrap(sv, strbuf, pos, pos, wrapwidth, editwidth); centerstr = sv->cur; updateflags = U_EDITAREA; } } else { /* easy replace */ if (centerstr->s[pos] == 0) { if (strlen(centerstr->s) < (wrapwidth?wrapwidth:editwidth)) { centerstr->s[pos+1] = 0; centerstr->s[pos++] = key; updateflags |= U_CENTER; } else if (wrapwidth) { /* no room; wordwrap */ strbuf[0] = key; strbuf[1] = 0; sv->cur = centerstr; pos = wordwrap(sv, strbuf, pos, pos, wrapwidth, editwidth); centerstr = sv->cur; updateflags = U_EDITAREA; } } else { centerstr->s[pos++] = key; updateflags |= U_CENTER; } } /* esle replace */ break; } } /* esle in editmode */ /* if the shift key is not still held down and we are selecting, * then stop select mode */ /* also stop if true ASCII key was pressed and selection is active */ if ((!selectFlag && selPos != -1) || (key < 0x7F && selPos != -1)) { selPos = -1; selLineOffset = 0; updateflags |= U_EDITAREA; } } /* elihw */ sv->cur = centerstr; return done; }
/** * @relates texteditor * @brief Play any ZZM music found in the editor. * * @param slurflag Slur notes together when true (ZZT-style). */ void texteditZZMPlay(texteditor * editor, int slurflag) { /** @TODO: do a damn good job of testing music */ /* Idea: create a copy of *editor so that we can mess around with curline and * pos and such, using existing functions to do the bulk of the display. */ #if 0 editor->text->cur = editor->curline; testMusic(editor->text, slurflag, editor->linewidth, flags, editor->d); #endif /* Create a new view of the editor data. This allows us to move the cursor * and change display settings for the new view without affecting editor. */ const char* playString = "#play "; const int playStringLen = 6; texteditor editorCopy = *editor; texteditor* view = &editorCopy; int done; #ifdef SDL SDL_AudioSpec spec; #endif /* Display everything, in case the editor has not been displayed recently. */ view->updateflags |= TUD_ALL; #ifdef SDL /* IF opening the audio device fails, return now before we crash something. */ if (OpenSynth(&spec)) return; #endif done = 0; /* Loop through the stringvector looking for #play statements */ while (view->curline != NULL && !done) { char* tune = strstr(view->curline->s, "#"); if (tune != NULL && str_equ(tune, playString, STREQU_UNCASE | STREQU_RFRONT)) { /* Current note and settings */ musicalNote note = zzmGetDefaultNote(); musicSettings settings = zzmGetDefaultSettings(); int xoffset = tune - view->curline->s + playStringLen; tune += playStringLen; /* Advance to notes! */ /* Change the slur setting */ note.slur = slurflag; while (note.src_pos < strlen(tune) && !done) { if (view->d->getkey() != DKEY_NONE) done = 1; /* Move the cursor and re-display before playing note. */ view->pos = note.src_pos + xoffset; texteditUpdateDisplay(view); note = zzmGetNote(tune, note); #ifdef DOS pcSpeakerPlayNote(note, settings); #elif defined SDL SynthPlayNote(spec, note, settings); #endif } } view->curline = view->curline->next; /* Re-display edit area since the current line has changed. */ view->updateflags |= TUD_EDITAREA; } #ifdef SDL /* TODO: instead of just sitting here, display the progress of playback */ /* Wait until the music is done or the user presses a key */ while (!IsSynthBufferEmpty() && view->d->getkey() == DKEY_NONE) ; CloseSynth(); #elif defined DOS pcSpeakerFinish(); #endif /* No need to free the view, it only exists on the stack. */ /* The edit area needs to be redisplayed now. */ editor->updateflags |= TUD_EDITAREA; }
int parameditoption_id(displaymethod * d, ZZTworld * w, ZZTtile tile, dialogComponent * opt) { int num; /* General use number */ switch (opt->id) { case ID_PROGRAM: editprogram(d, tile.param); return 2; case ZZT_DATAUSE_PASSAGEDEST: tile.param->data[2] = boarddialog(w, tile.param->data[2], "Passage Destination", 0, d); return 2; case ZZT_DATAUSE_CHAR: num = charselect(d, tile.param->data[0]); if (num != -1) tile.param->data[0] = num; return 1; case ZZT_DATAUSE_LOCKED: tile.param->data[1] = !tile.param->data[1]; return 1; /* 8-bit numbers */ case ZZT_DATAUSE_TIMELEFT: /* For values under ten, toggle between 0 and 9 */ if (tile.param->data[zztParamDatauseLocate(opt->id)] < 10) { if (tile.param->data[zztParamDatauseLocate(opt->id)] == 0) tile.param->data[zztParamDatauseLocate(opt->id)] = 9; else tile.param->data[zztParamDatauseLocate(opt->id)] = 0; return 1; } case ZZT_DATAUSE_DUPRATE: case ZZT_DATAUSE_SENSITIVITY: case ZZT_DATAUSE_INTELLIGENCE: case ZZT_DATAUSE_RESTTIME: case ZZT_DATAUSE_SPEED: case ZZT_DATAUSE_DEVIANCE: case ZZT_DATAUSE_STARTTIME: case ZZT_DATAUSE_PERIOD: /* Require user to inc/dec for values under 9 */ if (tile.param->data[zztParamDatauseLocate(opt->id)] < 9) return 0; case ID_CYCLE: case ID_DATA0: case ID_DATA1: case ID_DATA2: /* zero's are special */ if (str_equ(opt->text, "0", 0)) opt->text[0] = '\x0'; if (dialogComponentEdit(d, opt, 3, LINED_NUMBER) == LINED_OK) { sscanf(opt->text, "%d", &num); /* No exceeding the bounds of an 8-bit number */ if (num > 255) num = 255; /* zero's are special */ if (opt->text[0] == '\x0') num = 0; /* Is this lame, or what? */ /* We could put the above in a function and use * the top level switch only, but why bother? */ switch (opt->id) { case ID_CYCLE: tile.param->cycle = num; break; case ID_DATA0: tile.param->data[0] = num; break; case ID_DATA1: tile.param->data[1] = num; break; case ID_DATA2: tile.param->data[2] = num; break; default: tile.param->data[zztParamDatauseLocate(opt->id)] = num; break; } } return 1; /* signed 8-bit values -- ack! */ case ID_XSTEP: case ID_YSTEP: /* almost like regular 8-bits... */ /* zero's are special */ if (str_equ(opt->text, "0", 0)) opt->text[0] = '\x0'; if (dialogComponentEdit(d, opt, 4, LINED_SNUMBER) == LINED_OK) { sscanf(opt->text, "%d", &num); /* No exceeding the bounds of a signed 8-bit number */ if (num > 127) num = 127; if (num < -128) num = -128; /* zero's are special */ if (opt->text[0] == '\x0') num = 0; if (opt->id == ID_XSTEP) tile.param->xstep = num; else tile.param->ystep = num; } return 1; // c/p from above --GM case ID_XPOS: case ID_YPOS: /* almost like regular 8-bits... */ /* zero's are special */ if (str_equ(opt->text, "0", 0)) opt->text[0] = '\x0'; if (dialogComponentEdit(d, opt, 4, LINED_SNUMBER) == LINED_OK) { sscanf(opt->text, "%d", &num); /* No exceeding the bounds of a signed 8-bit number */ if (num > 127) num = 127; if (num < -128) num = -128; /* zero's are special */ if (opt->text[0] == '\x0') num = 0; if (opt->id == ID_XPOS) tile.param->x = num; else tile.param->y = num; } return 1; case ID_FIRERATE: if (str_equ(opt->text, "0", 0)) opt->text[0] = '\x0'; if (dialogComponentEdit(d, opt, 3, LINED_NUMBER) == LINED_OK) { int firerateindex = zztParamDatauseLocate(ZZT_DATAUSE_FIRERATEMODE); sscanf(opt->text, "%d", &num); /* No exceeding the bounds of a 7-bit number */ if (num > 127) num = 127; /* zero's are special */ if (opt->text[0] == '\x0') num = 0; tile.param->data[firerateindex] &= 0x80; tile.param->data[firerateindex] |= num; } return 1; case ID_BIND: num = tile.param->bindindex; if (num == 0) num = -1; /* For #bind, 0 means none */ num = paramlistdialog(d, zztBoardGetBlock(w), num, "Select object to bind with"); if (num == -1) num = 0; tile.param->bindindex = num; return 1; case ID_INSTRUCTION: /* zero's are special */ if (str_equ(opt->text, "0", 0)) opt->text[0] = '\x0'; if (dialogComponentEdit(d, opt, 6, LINED_SNUMBER) == LINED_OK) { sscanf(opt->text, "%d", &num); /* zero's are special */ if (opt->text[0] == '\x0') num = 0; tile.param->instruction = num; } return 1; case ID_LEADER: case ID_FOLLOWER: if (opt->id == ID_LEADER) num = tile.param->leaderindex; else num = tile.param->followerindex; if (num == 0xFFFF) num = -1; /* For #bind, 0 means none */ num = paramlistdialog(d, zztBoardGetBlock(w), num, "Select object to bind with"); if (num == -1) num = 0xFFFF; if (opt->id == ID_LEADER) tile.param->leaderindex = num; else tile.param->followerindex = num; return 1; case ID_PROJECTILE: tile.param->data[zztParamDatauseLocate(ZZT_DATAUSE_FIRERATEMODE)] ^= 0x80; return 1; case ZZT_DATAUSE_OWNER: tile.param->data[zztParamDatauseLocate(opt->id)] = !tile.param->data[zztParamDatauseLocate(opt->id)]; return 1; case ID_DIRECTION: { char xstep, ystep; num = getdirection(tile.param->xstep, tile.param->ystep); num = nextdirection(num); getxystep(&xstep, &ystep, num); tile.param->xstep = xstep; tile.param->ystep = ystep; } return 1; } /* No change occured if we reach this point */ return 0; }
void saveworld(displaymethod * mydisplay, ZZTworld * myworld) { /* Save World after prompting user for filename */ char* filename; char* path, * file; char* oldfilenamebase; /* Old filename without extension */ char* dotptr; /* General pointer */ filename = filenamedialog(zztWorldGetFilename(myworld), "zzt", "Save World As", 1, mydisplay); if (filename == NULL) return; path = (char*) malloc(sizeof(char) * (strlen(filename) + 1)); file = (char*) malloc(sizeof(char) * (strlen(filename) + 1)); fileof(file, filename, strlen(filename) + 1); pathof(path, filename, strlen(filename) + 1); /* Change to the selected path */ chdir(path); /* Update the title of the world to reflect the new filename if * the filename and title were the same previously. * That is, if they started out the same, keep them the same. */ /* Grab the base part of the original filename */ oldfilenamebase = str_dup(zztWorldGetFilename(myworld)); dotptr = strrchr(oldfilenamebase, '.'); if (dotptr != NULL) *dotptr = '\0'; if ((!str_equ(zztWorldGetFilename(myworld), file, STREQU_UNCASE) && str_equ(oldfilenamebase, zztWorldGetTitle(myworld), STREQU_UNCASE)) || str_equ("UNTITLED", zztWorldGetTitle(myworld), 0)) { char* newtitle = str_dup(file); dotptr = strrchr(newtitle, '.'); if (dotptr != NULL) *dotptr = '\0'; zztWorldSetTitle(myworld, newtitle); free(newtitle); } /* Update the filename used by the world */ zztWorldSetFilename(myworld, file); /* Set the current board as the starting board */ zztWorldSetStartboard(myworld, zztBoardGetCurrent(myworld)); zztWorldSave(myworld); free(oldfilenamebase); oldfilenamebase = NULL; free(filename); free(path); free(file); mydisplay->print(61, 5, 0x1f, "Written."); mydisplay->cursorgo(69, 5); mydisplay->getch(); }