/// SimpleMarkText() static void SimpleMarkText(struct InstData *data, LONG startx, struct line_node *startline, LONG stopx, struct line_node *stopline) { ENTER(); if(Enabled(data)) { data->blockinfo.enabled = FALSE; MarkText(data, data->blockinfo.startx, data->blockinfo.startline, data->blockinfo.stopx, data->blockinfo.stopline); } // else { SetCursor(data, data->CPos_X, data->actualline, FALSE); } data->blockinfo.startline = startline; data->blockinfo.startx = startx; data->blockinfo.stopline = data->actualline = stopline; data->blockinfo.stopx = data->CPos_X = stopx; data->blockinfo.enabled = TRUE; ScrollIntoDisplay(data); MarkText(data, startx, startline, stopx, stopline); LEAVE(); }
long Undo(struct InstData *data) { ENTER(); D(DBF_UNDO, "undolevel: %ld undocur: %ld undofill: %ld", data->undolevel, data->undocur, data->undofill); // check if there is something in the undo // buffer available if(data->undolevel > 0 && data->undocur > 0) { struct UserAction *buffer; BOOL crsr_move = TRUE; if(Enabled(data)) { data->blockinfo.enabled = FALSE; MarkText(data->blockinfo.startx, data->blockinfo.startline, data->blockinfo.stopx, data->blockinfo.stopline, data); } // as the redo operation automatically // becomes available when undo is used we just // check here if we didn't yet set RedoAvailable // as we only want to set it once if(data->undocur == data->undofill) set(data->object, MUIA_TextEditor_RedoAvailable, TRUE); data->undopointer = (APTR)((char *)data->undopointer - sizeof(struct UserAction)); data->undocur--; buffer = (struct UserAction *)data->undopointer; // if(data->actualline != LineNode(buffer->y, data) || data->CPos_X != buffer->x) SetCursor(data->CPos_X, data->actualline, FALSE, data); data->CPos_X = buffer->x; data->actualline = LineNode(buffer->y, data); ScrollIntoDisplay(data); switch(buffer->type) { case ET_PASTECHAR: { buffer->del.character = *(data->actualline->line.Contents+data->CPos_X); buffer->del.style = GetStyle(data->CPos_X, data->actualline); buffer->del.flow = data->actualline->line.Flow; buffer->del.separator = data->actualline->line.Separator; RemoveChars(data->CPos_X, data->actualline, 1, data); } break; case ET_BACKSPACECHAR: { PasteChars(data->CPos_X++, data->actualline, 1, (char *)&buffer->del.character, buffer, data); } break; case ET_DELETECHAR: { PasteChars(data->CPos_X, data->actualline, 1, (char *)&buffer->del.character, buffer, data); } break; case ET_SPLITLINE: { MergeLines(data->actualline, data); } break; case ET_MERGELINES: { SplitLine(data->CPos_X, data->actualline, FALSE, buffer, data); } break; case ET_BACKSPACEMERGE: { SplitLine(data->CPos_X, data->actualline, TRUE, buffer, data); } break; case ET_PASTEBLOCK: { struct marking block = { TRUE, LineNode(buffer->y, data), buffer->x, LineNode(buffer->blk.y, data), buffer->blk.x }; char *clip = GetBlock(&block, data); CutBlock2(data, FALSE, FALSE, &block, TRUE); buffer->clip = (unsigned char *)clip; } break; case ET_DELETEBLOCK_NOMOVE: crsr_move = FALSE; // continue case ET_DELETEBLOCK: { struct Hook *oldhook = data->ImportHook; char *clip = (char *)buffer->clip; data->ImportHook = &ImPlainHook; InsertText(data, clip, crsr_move); data->ImportHook = oldhook; MyFreePooled(data->mypool, clip); buffer->blk.x = data->CPos_X; buffer->blk.y = LineNr(data->actualline, data); if(!crsr_move) { data->CPos_X = buffer->x; data->actualline = LineNode(buffer->y, data); } } break; default: // nothing to do break; } ScrollIntoDisplay(data); if(data->flags & FLG_Active) SetCursor(data->CPos_X, data->actualline, TRUE, data); // if there are no further undo levels we // have to set UndoAvailable to FALSE if(data->undocur == 0) { set(data->object, MUIA_TextEditor_UndoAvailable, FALSE); if(!(data->flags & FLG_UndoLost)) data->HasChanged = FALSE; } RETURN(TRUE); return(TRUE); } else { DoMethod(data->object, MUIM_TextEditor_HandleError, Error_NothingToUndo); RETURN(FALSE); return(FALSE); } }
long Redo(struct InstData *data) { ENTER(); D(DBF_UNDO, "undolevel: %ld undocur: %ld undofill: %ld", data->undolevel, data->undocur, data->undofill); // check if there something to redo at all if(data->undofill > 0 && data->undocur < data->undofill) { struct UserAction *buffer = (struct UserAction *)data->undopointer; if(Enabled(data)) { data->blockinfo.enabled = FALSE; MarkText(data->blockinfo.startx, data->blockinfo.startline, data->blockinfo.stopx, data->blockinfo.stopline, data); } // in case undocur is equal zero then we have to // set the undoavailable attribute to true to signal // others that undo is available if(data->undocur == 0) set(data->object, MUIA_TextEditor_UndoAvailable, TRUE); data->undopointer = (APTR)((char *)data->undopointer + sizeof(struct UserAction)); data->undocur++; // if(data->actualline != LineNode(buffer->y, data) || data->CPos_X != buffer->x) SetCursor(data->CPos_X, data->actualline, FALSE, data); data->CPos_X = buffer->x; data->actualline = LineNode(buffer->y, data); ScrollIntoDisplay(data); switch(buffer->type) { case ET_PASTECHAR: PasteChars(data->CPos_X++, data->actualline, 1, (char *)&buffer->del.character, buffer, data); break; case ET_BACKSPACECHAR: case ET_DELETECHAR: RemoveChars(data->CPos_X, data->actualline, 1, data); break; case ET_SPLITLINE: SplitLine(data->CPos_X, data->actualline, TRUE, NULL, data); break; case ET_MERGELINES: case ET_BACKSPACEMERGE: MergeLines(data->actualline, data); break; case ET_PASTEBLOCK: { struct Hook *oldhook = data->ImportHook; data->ImportHook = &ImPlainHook; InsertText(data, (char *)buffer->clip, TRUE); data->ImportHook = oldhook; MyFreePooled(data->mypool, buffer->clip); buffer->blk.x = data->CPos_X; buffer->blk.y = LineNr(data->actualline, data); } break; case ET_DELETEBLOCK_NOMOVE: case ET_DELETEBLOCK: { struct marking block = { TRUE, LineNode(buffer->y, data), buffer->x, LineNode(buffer->blk.y, data), buffer->blk.x }; char *clip = GetBlock(&block, data); CutBlock2(data, FALSE, FALSE, &block, TRUE); buffer->clip = (unsigned char *)clip; } break; default: // nothing to do break; } ScrollIntoDisplay(data); if(data->flags & FLG_Active) SetCursor(data->CPos_X, data->actualline, TRUE, data); // if undocur == undofill this signals that we // don't have any things to redo anymore. if(data->undocur == data->undofill) set(data->object, MUIA_TextEditor_RedoAvailable, FALSE); RETURN(TRUE); return(TRUE); } else { DoMethod(data->object, MUIM_TextEditor_HandleError, Error_NothingToRedo); RETURN(FALSE); return(FALSE); } }
/*----------------------* * Paste from Clipboard * *----------------------*/ BOOL PasteClip (LONG x, struct line_node *actline, struct InstData *data) { struct line_node *line = NULL; struct line_node *startline = NULL; struct line_node *previous = NULL; UWORD *styles = NULL; UWORD *colors = NULL; STRPTR textline; BOOL newline = TRUE; BOOL res = FALSE; ENTER(); if(InitClipboard(data, IFFF_READ)) { if(StopChunk(data->iff, ID_FTXT, ID_CHRS) == 0 && StopChunk(data->iff, ID_FTXT, ID_FLOW) == 0 && StopChunk(data->iff, ID_FTXT, ID_HIGH) == 0 && StopChunk(data->iff, ID_FTXT, ID_SBAR) == 0 && StopChunk(data->iff, ID_FTXT, ID_COLS) == 0 && StopChunk(data->iff, ID_FTXT, ID_STYL) == 0 && StopChunk(data->iff, ID_FTXT, ID_CSET) == 0) { LONG error, codeset = 0; UWORD flow = MUIV_TextEditor_Flow_Left; UWORD color = FALSE; UWORD separator = 0; BOOL ownclip = FALSE; LONG updatefrom; while(TRUE) { struct ContextNode *cn; error = ParseIFF(data->iff, IFFPARSE_SCAN); SHOWVALUE(DBF_CLIPBOARD, error); if(error == IFFERR_EOC) continue; else if(error) break; if((cn = CurrentChunk(data->iff)) != NULL) { switch (cn->cn_ID) { case ID_CSET: D(DBF_CLIPBOARD, "reading FLOW"); SHOWVALUE(DBF_CLIPBOARD, cn->cn_Size); if(cn->cn_Size >= 4) { /* Only the first four bytes are interesting */ if(ReadChunkBytes(data->iff, &codeset, 4) != 4) { codeset = 0; } SHOWVALUE(DBF_CLIPBOARD, codeset); } break; case ID_FLOW: D(DBF_CLIPBOARD, "reading FLOW"); SHOWVALUE(DBF_CLIPBOARD, cn->cn_Size); if(cn->cn_Size == 2) { if(ReadChunkBytes(data->iff, &flow, 2) == 2) if(flow > MUIV_TextEditor_Flow_Right) flow = MUIV_TextEditor_Flow_Left; SHOWVALUE(DBF_CLIPBOARD, flow); } break; case ID_HIGH: D(DBF_CLIPBOARD, "reading HIGH"); SHOWVALUE(DBF_CLIPBOARD, cn->cn_Size); if (cn->cn_Size == 2) { error = ReadChunkBytes(data->iff, &color, 2); SHOWVALUE(DBF_CLIPBOARD, color); SHOWVALUE(DBF_CLIPBOARD, error); } break; case ID_SBAR: D(DBF_CLIPBOARD, "reading SBAR"); SHOWVALUE(DBF_CLIPBOARD, cn->cn_Size); if (cn->cn_Size == 2) { error = ReadChunkBytes(data->iff, &separator, 2); SHOWVALUE(DBF_CLIPBOARD, separator); SHOWVALUE(DBF_CLIPBOARD, error); } break; case ID_COLS: D(DBF_CLIPBOARD, "reading COLS"); SHOWVALUE(DBF_CLIPBOARD, cn->cn_Size); if(colors) { MyFreePooled(data->mypool, colors); colors = NULL; } // allocate one word more than the chunk tell us, because we terminate the array with an additional value if(cn->cn_Size > 0 && (colors = (UWORD *)MyAllocPooled(data->mypool, cn->cn_Size + sizeof(UWORD))) != NULL) { error = ReadChunkBytes(data->iff, colors, cn->cn_Size); SHOWVALUE(DBF_CLIPBOARD, error); colors[cn->cn_Size / 2] = 0xffff; } break; case ID_STYL: D(DBF_CLIPBOARD, "reading STYL"); SHOWVALUE(DBF_CLIPBOARD, cn->cn_Size); ownclip = TRUE; if(styles) { MyFreePooled(data->mypool, styles); styles = NULL; } // allocate one word more than the chunk tell us, because we terminate the array with an additional value if(cn->cn_Size > 0 && (styles = (UWORD *)MyAllocPooled(data->mypool, cn->cn_Size + sizeof(UWORD))) != NULL) { error = ReadChunkBytes(data->iff, styles, cn->cn_Size); SHOWVALUE(DBF_CLIPBOARD, error); styles[cn->cn_Size / 2] = EOS; } break; case ID_CHRS: { D(DBF_CLIPBOARD, "reading CHRS"); SHOWVALUE(DBF_CLIPBOARD, cn->cn_Size); data->HasChanged = TRUE; if(cn->cn_Size > 0 && !ownclip) { char *contents; ULONG length = cn->cn_Size; if((contents = (char *)MyAllocPooled(data->mypool, length + 1)) != NULL) { error = ReadChunkBytes(data->iff, contents, length); SHOWVALUE(DBF_CLIPBOARD, error); if(contents[length - 1] != '\n') { newline = FALSE; } else { length--; } contents[length] = '\0'; #if defined(__MORPHOS__) if (codeset == CODESET_UTF8) { if (IS_MORPHOS2) contents = utf8_to_ansi(data, contents); } #endif if((line = ImportText(contents, data, &ImPlainHook, data->ImportWrap))) { if(!startline) startline = line; if(previous) previous->next = line; line->previous = previous; line->visual = VisualHeight(line, data); data->totallines += line->visual; while(line->next) { line = line->next; line->visual = VisualHeight(line, data); data->totallines += line->visual; } previous = line; } MyFreePooled(data->mypool, contents); } } else { ULONG length = cn->cn_Size; if(length > 0 && (textline = (char *)MyAllocPooled(data->mypool, length + 2)) != NULL) { error = ReadChunkBytes(data->iff, textline, length); SHOWVALUE(DBF_CLIPBOARD, error); if (textline[length - 1] != '\n') { newline = FALSE; textline[length] = '\n'; length++; } textline[length] = '\0'; if((line = AllocLine(data))) { line->next = NULL; line->previous = previous; line->line.Contents = textline; line->line.Length = length; line->visual = VisualHeight(line, data); line->line.Color = color; line->line.Flow = flow; line->line.Separator = separator; line->line.Styles = styles; line->line.Colors = colors; data->totallines += line->visual; if(!startline) startline = line; if(previous) previous->next = line; previous = line; } else { if(styles) MyFreePooled(data->mypool, (void *)styles); if(colors) MyFreePooled(data->mypool, (void *)colors); } } else { if(styles) MyFreePooled(data->mypool, styles); if(colors) MyFreePooled(data->mypool, (void *)colors); } styles = NULL; colors = NULL; flow = MUIV_TextEditor_Flow_Left; color = FALSE; separator = 0; ownclip = FALSE; } } break; } } } if(line) { BOOL oneline = FALSE; SplitLine(x, actline, FALSE, NULL, data); line->next = actline->next; actline->next->previous = line; actline->next = startline; startline->previous = actline; data->CPos_X = line->line.Length-1; if(actline->next == line) { data->CPos_X += actline->line.Length-1; oneline = TRUE; } if(!newline) MergeLines(line, data); MergeLines(actline, data); if(oneline) line = actline; if(newline) { line = line->next; data->CPos_X = 0; } data->actualline = line; } else { switch(error) { case IFFERR_MANGLED: case IFFERR_SYNTAX: case IFFERR_NOTIFF: D(DBF_CLIPBOARD, "no FTXT clip!"); DoMethod(data->object, MUIM_TextEditor_HandleError, Error_ClipboardIsNotFTXT); break; default: D(DBF_CLIPBOARD, "clipboard is empty!"); DoMethod(data->object, MUIM_TextEditor_HandleError, Error_ClipboardIsEmpty); break; } } data->update = TRUE; ScrollIntoDisplay(data); updatefrom = LineToVisual(actline, data)-1; if(updatefrom < 0) updatefrom = 0; DumpText(data->visual_y+updatefrom, updatefrom, data->maxlines, TRUE, data); if(data->update) res = TRUE; else data->update = TRUE; } EndClipSession(data); } RETURN(res); return res; }
static void UpdateChange(LONG x, struct line_node *line, LONG length, const char *characters, struct UserAction *buffer, struct InstData *data) { LONG diff; LONG skip=0; LONG line_nr; LONG orgline_nr; LONG width=0; LONG lineabove_width=0; ENTER(); line_nr = LineToVisual(line, data); orgline_nr = line_nr; do { // don't exceed the line length! if(skip > (LONG)line->line.Length) break; width = LineCharsWidth(line->line.Contents + skip, data); if(width > 0 && skip + width < x) { lineabove_width = width; skip += width; line_nr++; } else break; } while(TRUE); if(characters != NULL) { strcpyback(line->line.Contents+x+length, line->line.Contents+x); memcpy(line->line.Contents+x, characters, length); width += length; line->line.Length += length; if(buffer != NULL) { UWORD style = buffer->del.style; AddStyleToLine(x, line, 1, (style & BOLD) ? BOLD : ~BOLD, data); AddStyleToLine(x, line, 1, (style & ITALIC) ? ITALIC : ~ITALIC, data); AddStyleToLine(x, line, 1, (style & UNDERLINE) ? UNDERLINE : ~UNDERLINE, data); line->line.Flow = buffer->del.flow; line->line.Separator = buffer->del.separator; } } else { strlcpy(line->line.Contents+x, line->line.Contents+x+length, line->line.Length); width -= length; line->line.Length -= length; } diff = VisualHeight(line, data) - line->visual; if(diff != 0) { LONG movement; movement = orgline_nr + line->visual - 1; line->visual += diff; data->totallines += diff; if(diff > 0) { if(movement < data->maxlines) ScrollDown(movement, diff, data); } else { movement = orgline_nr + line->visual - 1; if(movement <= data->maxlines) ScrollUp(movement, -diff, data); } } if(orgline_nr != line_nr) { if(lineabove_width != LineCharsWidth(line->line.Contents+skip-lineabove_width, data)) { LONG newwidth; newwidth = PrintLine(skip-lineabove_width, line, line_nr-1, TRUE, data) - lineabove_width; skip += newwidth; width -= newwidth; if(skip >= (LONG)line->line.Length) { LEAVE(); return; } } } OptimizedPrint(skip, line, line_nr, width, data); ScrollIntoDisplay(data); data->HasChanged = TRUE; LEAVE(); }
LONG CutBlock2(struct InstData *data, BOOL Clipboard, BOOL NoCut, struct marking *newblock, BOOL update) { LONG tvisual_y, error; LONG startx, stopx; LONG res = 0; struct line_node *startline, *stopline; ENTER(); startx = newblock->startx; stopx = newblock->stopx; startline = newblock->startline; stopline = newblock->stopline; //D(DBF_STARTUP, "CutBlock2: %ld-%ld %lx-%lx %ld %ld", startx, stopx, startline, stopline, Clipboard, NoCut); if(startline != stopline) { struct line_node *c_startline = startline->next; data->update = FALSE; if(Clipboard == TRUE) { if(InitClipboard(data, IFFF_WRITE)) { D(DBF_CLIPBOARD, "writing FORM"); error = PushChunk(data->iff, ID_FTXT, ID_FORM, IFFSIZE_UNKNOWN); SHOWVALUE(DBF_CLIPBOARD, error); ClipChars(startx, startline, startline->line.Length-startx, data); } else { Clipboard = FALSE; } } while(c_startline != stopline) { if(Clipboard == TRUE) { ClipLine(c_startline, data); } if(NoCut == FALSE) { struct line_node *cc_startline = c_startline; MyFreePooled(data->mypool, c_startline->line.Contents); if(c_startline->line.Styles != NULL) MyFreePooled(data->mypool, c_startline->line.Styles); data->totallines -= c_startline->visual; c_startline = c_startline->next; //D(DBF_STARTUP, "FreeLine %08lx", cc_startline); FreeLine(cc_startline, data); } else c_startline = c_startline->next; } if(Clipboard == TRUE) { if(stopx != 0) ClipChars(0, stopline, stopx, data); EndClipSession(data); } if(NoCut == FALSE) { startline->next = stopline; stopline->previous = startline; //D(DBF_STARTUP, "RemoveChars: %ld %ld %08lx %ld", startx, stopx, startline, startline->line.Length); if(startline->line.Length-startx-1 > 0) RemoveChars(startx, startline, startline->line.Length-startx-1, data); if(stopx != 0) RemoveChars(0, stopline, stopx, data); data->CPos_X = startx; data->actualline = startline; MergeLines(startline, data); } } else { if(Clipboard == TRUE) { if(InitClipboard(data, IFFF_WRITE)) { D(DBF_CLIPBOARD, "writing FORM"); error = PushChunk(data->iff, ID_FTXT, ID_FORM, IFFSIZE_UNKNOWN); SHOWVALUE(DBF_CLIPBOARD, error); ClipChars(startx, startline, stopx-startx, data); EndClipSession(data); } if(update == TRUE && NoCut == TRUE) { MarkText(data->blockinfo.startx, data->blockinfo.startline, data->blockinfo.stopx, data->blockinfo.stopline, data); goto end; } } if(NoCut == FALSE) { data->CPos_X = startx; RemoveChars(startx, startline, stopx-startx, data); if(update == TRUE) goto end; } } tvisual_y = LineToVisual(startline, data)-1; if(tvisual_y < 0 || tvisual_y > data->maxlines) { //D(DBF_STARTUP, "ScrollIntoDisplay"); ScrollIntoDisplay(data); tvisual_y = 0; } if(update == TRUE) { //D(DBF_STARTUP, "DumpText! %ld %ld %ld", data->visual_y, tvisual_y, data->maxlines); data->update = TRUE; DumpText(data->visual_y+tvisual_y, tvisual_y, data->maxlines, TRUE, data); } res = tvisual_y; end: RETURN(res); return res; }