void ResetUndoBuffer(struct InstData *data) { ENTER(); if(data->undosize != 0) { struct UserAction *buffer = (struct UserAction *)data->undobuffer; while(data->undocur > 0) { if(buffer->type == ET_DELETEBLOCK) MyFreePooled(data->mypool, buffer->clip); buffer++; data->undocur--; data->undofill--; } while(data->undofill > 0) { if(buffer->type == ET_PASTEBLOCK) MyFreePooled(data->mypool, buffer->clip); buffer++; data->undofill--; } data->undopointer = data->undobuffer; ASSERT(data->undocur == 0); ASSERT(data->undofill == 0); } LEAVE(); }
void ResizeUndoBuffer(struct InstData *data, ULONG level) { ENTER(); if(data->undolevel != level) { D(DBF_UNDO, "resizing undo buffer for %ld undo levels", level); if(data->undobuffer != NULL) { ResetUndoBuffer(data); MyFreePooled(data->mypool, data->undobuffer); } data->undobuffer = NULL; data->undopointer = NULL; data->undosize = 0; data->undofill = 0; data->undocur = 0; data->undolevel = level; if(level > 0) { ULONG newSize; // calculate number of bytes from number of undo levels newSize = (level * sizeof(struct UserAction)); // allocate a new undo buffer if((data->undobuffer = MyAllocPooled(data->mypool, newSize)) != NULL) { data->undopointer = data->undobuffer; data->undosize = newSize; } } } 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 AddToUndoBuffer(enum EventType eventtype, char *eventdata, struct InstData *data) { ENTER(); D(DBF_UNDO, "undolevel: %ld undocur: %ld undofill: %ld", data->undolevel, data->undocur, data->undofill); if(data->undolevel > 0) { struct UserAction *buffer; // check if there is still enough space in our undo buffer // and if not we clean it up a bit (10 entries) if(data->undofill+1 > data->undolevel) { ULONG c; char *t_undobuffer = (char *)data->undobuffer; // cleanup at most the first 10 entries in our undobuffer for(c=0; c < 10 && data->undofill > 0; c++) { struct UserAction *t_buffer = (struct UserAction *)t_undobuffer; if(t_buffer->type == ET_DELETEBLOCK) MyFreePooled(data->mypool, t_buffer->clip); t_undobuffer += sizeof(struct UserAction); data->undocur--; data->undofill--; } D(DBF_UNDO, "undobuffer was filled up, cleaned up the first %ld entries", c+1); if(data->undofill > 0) { // copy everything from t_undobuffer to our start of the // undobuffer and set the undopointer accordingly. memcpy(data->undobuffer, t_undobuffer, data->undosize-(t_undobuffer-(char *)data->undobuffer)); data->undopointer = (APTR)(t_undobuffer - (char *)data->undopointer); } // signal the user that something in the // undo buffer was lost. data->flags |= FLG_UndoLost; } buffer = data->undopointer; // as we are about to set something new for an undo // operation we have to signal that redo operation // is cleared now. if(data->undocur < data->undofill) { char *t_undobuffer = (char *)data->undopointer; D(DBF_UNDO, "cleaning up %ld dropped undo nodes", data->undofill-data->undocur); // we have to first cleanup each buffer of the ET_PASTEBLOCK // event or otherwise we lost some memory. while(data->undofill > data->undocur) { struct UserAction *t_buffer = (struct UserAction *)t_undobuffer; if(t_buffer->type == ET_PASTEBLOCK) { D(DBF_UNDO, "cleaning uf paste buffer of user action %08lx", t_buffer); MyFreePooled(data->mypool, t_buffer->clip); } t_undobuffer += sizeof(struct UserAction); data->undofill--; } set(data->object, MUIA_TextEditor_RedoAvailable, FALSE); } // if undocur is zero we have to send the undoavailable // signal if(data->undocur == 0) set(data->object, MUIA_TextEditor_UndoAvailable, TRUE); data->undopointer = (APTR)((char *)data->undopointer + sizeof(struct UserAction)); data->undocur++; data->undofill = data->undocur; buffer->x = data->CPos_X; buffer->y = LineNr(data->actualline, data); buffer->type = eventtype; switch(eventtype) { case ET_BACKSPACEMERGE: case ET_MERGELINES: { buffer->del.style = data->actualline->next->line.Color; buffer->del.flow = data->actualline->next->line.Flow; buffer->del.separator = data->actualline->next->line.Separator; } break; case ET_DELETECHAR: case ET_BACKSPACECHAR: { buffer->del.character = *eventdata; buffer->del.style = GetStyle(data->CPos_X, data->actualline); buffer->del.flow = data->actualline->line.Flow; buffer->del.separator = data->actualline->line.Separator; } break; case ET_PASTEBLOCK: { struct marking *block = (struct marking *)eventdata; buffer->x = block->startx; buffer->y = LineNr(block->startline, data); buffer->blk.x = block->stopx; buffer->blk.y = LineNr(block->stopline, data); } break; case ET_DELETEBLOCK: { char *text; struct marking *block = (struct marking *)eventdata; if((text = GetBlock((struct marking *)eventdata, data))) { buffer->x = block->startx; buffer->y = LineNr(block->startline, data); buffer->clip = (unsigned char *)text; if(data->flags & FLG_FreezeCrsr) buffer->type = ET_DELETEBLOCK_NOMOVE; } else { ResetUndoBuffer(data); DoMethod(data->object, MUIM_TextEditor_HandleError, Error_NotEnoughUndoMem); } } break; default: // nothing to do break; } } RETURN(TRUE); return(TRUE); }
/*--------------------------* * Merge two lines into one * *--------------------------*/ BOOL MergeLines(struct line_node *line, struct InstData *data) { struct line_node *next; char *newbuffer; LONG visual, oldvisual, line_nr; LONG emptyline = FALSE; LONG color = line->line.Color; UWORD flow = line->line.Flow; UWORD separator = line->line.Separator; ENTER(); data->HasChanged = TRUE; if(line->line.Length == 1) { emptyline = TRUE; color = line->next->line.Color; flow = line->next->line.Flow; separator = line->next->line.Separator; } visual = line->visual + line->next->visual; if((newbuffer = MyAllocPooled(data->mypool, line->line.Length+line->next->line.Length+1)) != NULL) { memcpy(newbuffer, line->line.Contents, line->line.Length-1); memcpy(newbuffer+line->line.Length-1, line->next->line.Contents, line->next->line.Length+1); MyFreePooled(data->mypool, line->line.Contents); MyFreePooled(data->mypool, line->next->line.Contents); if(emptyline == TRUE) { if(line->line.Styles != NULL) MyFreePooled(data->mypool, line->line.Styles); line->line.Styles = line->next->line.Styles; if(line->line.Colors != NULL) MyFreePooled(data->mypool, line->line.Colors); line->line.Colors = line->next->line.Colors; } else { UWORD *styles; UWORD *styles1 = line->line.Styles; UWORD *styles2 = line->next->line.Styles; UWORD *colors; UWORD *colors1 = line->line.Colors; UWORD *colors2 = line->next->line.Colors; UWORD length = 12; if(styles1 != NULL) length += *((long *)styles1-1) - 4; if(styles2 != NULL) length += *((long *)styles2-1) - 4; if((styles = MyAllocPooled(data->mypool, length)) != NULL) { unsigned short* t_styles = styles; unsigned short style = 0; SHOWVALUE(DBF_CLIPBOARD, length); SHOWVALUE(DBF_CLIPBOARD, styles); SHOWVALUE(DBF_CLIPBOARD, styles1); SHOWVALUE(DBF_CLIPBOARD, styles2); if(styles2 != NULL) { unsigned short* t_styles2 = styles2; while(*t_styles2++ == 1) { if(*t_styles2 > 0xff) style &= *t_styles2++; else style |= *t_styles2++; } } if(styles1 != NULL) { while(*styles1 != EOS) { if((*styles1 == line->line.Length) && ((~*(styles1+1) & style) == (*(styles1+1) ^ 0xffff))) { style &= *(styles1+1); styles1 += 2; } else { *styles++ = *styles1++; *styles++ = *styles1++; } } SHOWVALUE(DBF_CLIPBOARD, line->line.Styles); MyFreePooled(data->mypool, line->line.Styles); } if(styles2 != NULL) { while(*styles2 != EOS) { if((*styles2 == 1) && (!(*(styles2+1) & style))) { styles2 += 2; } else { *styles++ = *styles2++ + line->line.Length - 1; *styles++ = *styles2++; } } SHOWVALUE(DBF_CLIPBOARD, line->next->line.Styles); MyFreePooled(data->mypool, line->next->line.Styles); } *styles = EOS; line->line.Styles = t_styles; } length = 12; if(colors1 != NULL) length += *((long *)colors1-1) - 4; if(colors2 != NULL) length += *((long *)colors2-1) - 4; if((colors = MyAllocPooled(data->mypool, length)) != NULL) { UWORD *t_colors = colors; UWORD end_color = 0; SHOWVALUE(DBF_CLIPBOARD, length); SHOWVALUE(DBF_CLIPBOARD, colors); SHOWVALUE(DBF_CLIPBOARD, colors1); SHOWVALUE(DBF_CLIPBOARD, colors2); if(colors1 != NULL) { while(*colors1 < line->line.Length && *colors1 != 0xffff) { *colors++ = *colors1++; end_color = *colors1; *colors++ = *colors1++; } SHOWVALUE(DBF_CLIPBOARD, line->line.Colors); MyFreePooled(data->mypool, line->line.Colors); } if(end_color && (colors2 == NULL || *colors2 != 1)) { *colors++ = line->line.Length; *colors++ = 0; } if(colors2 != NULL) { if(*colors2 == 1 && *(colors2+1) == end_color) colors2 += 2; while(*colors2 != 0xffff) { *colors++ = *colors2++ + line->line.Length - 1; *colors++ = *colors2++; } SHOWVALUE(DBF_CLIPBOARD, line->next->line.Colors); MyFreePooled(data->mypool, line->next->line.Colors); } *colors = 0xffff; line->line.Colors = t_colors; } } line->line.Contents = newbuffer; line->line.Length = strlen(newbuffer); next = line->next; line->next = line->next->next; if(line->next != NULL) line->next->previous = line; oldvisual = line->visual; line->visual = VisualHeight(line, data); line->line.Color = color; line->line.Flow = flow; line->line.Separator = separator; FreeLine(next, data); line_nr = LineToVisual(line, data); // handle that we have to scroll up/down due to word wrapping // that occurrs when merging lines if(visual > line->visual) { data->totallines -= 1; if(line_nr+line->visual-1 < data->maxlines) { if(emptyline && line_nr > 0) { if(data->fastbackground) { ScrollUp(line_nr - 1, 1, data); SetCursor(data->CPos_X, data->actualline, TRUE, data); } else DumpText(data->visual_y+line_nr-1, line_nr-1, data->maxlines, TRUE, data); } else { if(data->fastbackground) ScrollUp(line_nr + line->visual - 1, 1, data); else DumpText(data->visual_y+line_nr+line->visual-1, line_nr+line->visual-1, data->maxlines, TRUE, data); } } } else if(visual < line->visual) { data->totallines += 1; if(line_nr+line->visual-1 < data->maxlines) ScrollDown(line_nr + line->visual - 2, 1, data); } if(!(emptyline && (line_nr + line->visual - 1 < data->maxlines))) { LONG t_oldvisual = oldvisual; LONG t_line_nr = line_nr; ULONG c = 0; while((--t_oldvisual) && (t_line_nr++ <= data->maxlines)) c = c + LineCharsWidth(line->line.Contents+c, data); while((c < line->line.Length) && (t_line_nr <= data->maxlines)) c = c + PrintLine(c, line, t_line_nr++, TRUE, data); } if(line_nr + oldvisual == 1 && line->visual == visual-1) { data->visual_y--; data->totallines -= 1; if(data->fastbackground) DumpText(data->visual_y, 0, visual-1, TRUE, data); else DumpText(data->visual_y, 0, data->maxlines, TRUE, data); } RETURN(TRUE); return(TRUE); } else { 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); } }
static char *utf8_to_ansi(struct InstData *data, STRPTR src) { static struct KeyMap *keymap; CONST_STRPTR ptr; STRPTR dst; ULONG octets, strlength; ENTER(); keymap = AskKeyMapDefault(); strlength = 0; ptr = src; do { WCHAR wc; UBYTE c; ptr += (octets = UTF8_Decode(ptr, &wc)); c = ToANSI(wc, keymap); strlength++; /* ToANSI() returns '?' if there is not matching code point in the current keymap */ if (c == '?' && wc != '?') { /* If direct conversion fails try compatibility decomposition (but without recursion) */ CONST_WSTRPTR p = UCS4_Decompose(wc); if (p) { while (p[1]) { strlength++; p++; } } } } while (octets > 0); dst = MyAllocPooled(data->mypool, strlength); if (dst) { STRPTR bufptr = dst; ptr = src; do { WCHAR wc; UBYTE c; ptr += (octets = UTF8_Decode(ptr, &wc)); c = ToANSI(wc, keymap); *bufptr++ = c; if (c == '?' && wc != '?') { CONST_WSTRPTR p = UCS4_Decompose(wc); if (p) { bufptr--; while (*p) { *bufptr++ = ToANSI(*p, keymap); p++; } } } } while (octets > 0); MyFreePooled(data->mypool, src); // Free original buffer } if(dst == NULL) dst = src; RETURN(dst); return dst; }
/*----------------------* * 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; }
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; }
char *GetBlock(struct marking *block, struct InstData *data) { LONG startx, stopx; struct line_node *startline, *stopline, *act; char *text = NULL; struct ExportMessage emsg; ENTER(); startx = block->startx; stopx = block->stopx; startline = block->startline; stopline = block->stopline; data->CPos_X = startx; data->actualline = startline; // clear the export message memset(&emsg, 0, sizeof(struct ExportMessage)); // fill it afterwards emsg.UserData = NULL; emsg.ExportWrap = 0; emsg.Last = FALSE; emsg.data = data; if(startline != stopline) { /* Create a firstline look-a-like */ emsg.Contents = (STRPTR)MyAllocPooled(data->mypool, startline->line.Length-startx); if(startline->line.Styles && *startline->line.Styles != EOS) { ULONG startstyle = GetStyle(startx, startline); if((emsg.Styles = (UWORD *)MyAllocPooled(data->mypool, *((ULONG *)startline->line.Styles-1)+16))) { UWORD *styles = emsg.Styles, *oldstyles = startline->line.Styles; if(startstyle & BOLD) { *styles++ = 1; *styles++ = BOLD; } if(startstyle & ITALIC) { *styles++ = 1; *styles++ = ITALIC; } if(startstyle & UNDERLINE) { *styles++ = 1; *styles++ = UNDERLINE; } while(*oldstyles <= startx) oldstyles += 2; while(*oldstyles != EOS) { *styles++ = *oldstyles++ - startx; *styles++ = *oldstyles++; } *styles = EOS; } } else emsg.Styles = NULL; emsg.Colors = NULL; if(emsg.Contents) { memcpy(emsg.Contents, startline->line.Contents + startx, startline->line.Length - startx); emsg.Length = startline->line.Length - startx; emsg.Flow = startline->line.Flow; emsg.Separator = startline->line.Separator; emsg.Highlight = startline->line.Color; emsg.UserData = (APTR)CallHookA(&ExportHookPlain, NULL, &emsg); MyFreePooled(data->mypool, emsg.Contents); } if(emsg.Styles) MyFreePooled(data->mypool, emsg.Styles); /* Start iterating... */ act = startline->next; while(act != stopline) { emsg.Contents = act->line.Contents; emsg.Length = act->line.Length; emsg.Styles = act->line.Styles; emsg.Colors = act->line.Colors; emsg.Flow = act->line.Flow; emsg.Separator = act->line.Separator; emsg.Highlight = act->line.Color; emsg.UserData = (APTR)CallHookA(&ExportHookPlain, (APTR)NULL, &emsg); act = act->next; } /* Create a Lastline look-a-like */ emsg.Contents = (STRPTR)MyAllocPooled(data->mypool, stopx); if(stopline->line.Styles && *stopline->line.Styles != EOS) { ULONG stopstyle = GetStyle(stopx, stopline); if((emsg.Styles = (UWORD *)MyAllocPooled(data->mypool, *((ULONG *)stopline->line.Styles-1)+16))) { UWORD *styles = emsg.Styles, *oldstyles = stopline->line.Styles; while(*oldstyles <= stopx) { *styles++ = *oldstyles++; *styles++ = *oldstyles++; } if(stopstyle & BOLD) { *styles++ = stopx+1; *styles++ = ~BOLD; } if(stopstyle & ITALIC) { *styles++ = stopx+1; *styles++ = ~ITALIC; } if(stopstyle & UNDERLINE) { *styles++ = stopx+1; *styles++ = ~UNDERLINE; } *styles = EOS; } } else emsg.Styles = NULL; emsg.Colors = NULL; if(emsg.Contents) { memcpy(emsg.Contents, stopline->line.Contents, stopx); emsg.Length = stopx; emsg.Flow = stopline->line.Flow; emsg.Separator = stopline->line.Separator; emsg.Highlight = stopline->line.Color; emsg.Last = TRUE; text = (STRPTR)CallHookA(&ExportHookPlain, NULL, &emsg); MyFreePooled(data->mypool, emsg.Contents); } if(emsg.Styles) MyFreePooled(data->mypool, emsg.Styles); } else { /* Create a single line */ emsg.Contents = (STRPTR)MyAllocPooled(data->mypool, stopx-startx); if(startline->line.Styles && *startline->line.Styles != EOS) { ULONG startstyle = GetStyle(startx, startline); ULONG stopstyle = GetStyle(stopx, stopline); if((emsg.Styles = (UWORD *)MyAllocPooled(data->mypool, *((ULONG *)startline->line.Styles-1)))) { UWORD *styles = emsg.Styles, *oldstyles = startline->line.Styles; if(startstyle & BOLD) { *styles++ = 1; *styles++ = BOLD; } if(startstyle & ITALIC) { *styles++ = 1; *styles++ = ITALIC; } if(startstyle & UNDERLINE) { *styles++ = 1; *styles++ = UNDERLINE; } while(*oldstyles <= startx) oldstyles += 2; while(*oldstyles <= stopx) { *styles++ = *oldstyles++ - startx; *styles++ = *oldstyles++; } if(stopstyle & BOLD) { *styles++ = stopx-startx+1; *styles++ = ~BOLD; } if(stopstyle & ITALIC) { *styles++ = stopx-startx+1; *styles++ = ~ITALIC; } if(stopstyle & UNDERLINE) { *styles++ = stopx-startx+1; *styles++ = ~UNDERLINE; } *styles = EOS; } } else emsg.Styles = NULL; emsg.Colors = NULL; if(emsg.Contents) { memcpy(emsg.Contents, startline->line.Contents+startx, stopx-startx); emsg.Length = stopx-startx; emsg.Flow = startline->line.Flow; emsg.Separator = startline->line.Separator; emsg.Highlight = startline->line.Color; emsg.Last = TRUE; text = (STRPTR)CallHookA(&ExportHookPlain, NULL, &emsg); MyFreePooled(data->mypool, emsg.Contents); } if(emsg.Styles) MyFreePooled(data->mypool, emsg.Styles); } RETURN(text); return(text); }
HOOKPROTONO(ExportHookFunc, STRPTR, struct ExportMessage *emsg) { struct Buffer *buf = emsg->UserData; LONG length; UWORD *styles = emsg->Styles; UWORD *colors = emsg->Colors; UWORD lastpos = 0; UWORD currentstyle = 0; STRPTR result = NULL; STRPTR startx; struct InstData *data = emsg->data; LONG expand; ULONG hookType = (ULONG)hook->h_Data; ENTER(); if(buf == NULL) { if(data != NULL) { buf = MyAllocPooled(data->mypool, sizeof(struct Buffer)); if(buf != NULL) { buf->buffer = MyAllocPooled(data->mypool, 512); buf->size = 512; } } else { buf = AllocVec(sizeof(struct Buffer), MEMF_SHARED|MEMF_CLEAR); if(buf != NULL) { buf->buffer = AllocVec(1024, MEMF_SHARED|MEMF_CLEAR); buf->size = 1024; } } if(buf != NULL) { buf->pointer = buf->buffer; buf->flow = 0; } } if(buf != NULL && buf->buffer != NULL) { expand = 10*emsg->Length; if(buf->buffer+buf->size < buf->pointer+expand) { STRPTR oldbuf = buf->buffer; ULONG oldsize = buf->size; ULONG offset = buf->pointer - oldbuf; if(data) { buf->buffer = MyAllocPooled(data->mypool, oldsize+expand+512); buf->size = oldsize+expand+512; } else { buf->buffer = AllocVec(oldsize+expand+1024, MEMF_SHARED|MEMF_CLEAR); buf->size = oldsize+expand+1024; } buf->pointer = buf->buffer+offset; memcpy(buf->buffer, oldbuf, offset); if(data) MyFreePooled(data->mypool, oldbuf); else FreeVec(oldbuf); } // if this hook is of plain type we have consider highlighting as well. if(emsg->Highlight && hookType == MUIV_TextEditor_ExportHook_Plain) { *buf->pointer++ = '\033'; *buf->pointer++ = 'h'; } if(hookType == MUIV_TextEditor_ExportHook_Plain && emsg->Flow != buf->flow) { *buf->pointer++ = '\033'; switch(emsg->Flow) { case MUIV_TextEditor_Flow_Right: *buf->pointer++ = 'r'; break; case MUIV_TextEditor_Flow_Center: *buf->pointer++ = 'c'; break; case MUIV_TextEditor_Flow_Left: default: *buf->pointer++ = 'l'; } buf->flow = emsg->Flow; } if(emsg->Separator) { if(hookType == MUIV_TextEditor_ExportHook_Plain) snprintf(buf->pointer, buf->size-(buf->pointer-buf->buffer), "\033[s:%d]", emsg->Separator); else strlcpy(buf->pointer, ((emsg->Separator & LNSF_Thick) ? "<tsb>" : "<sb>"), buf->size-(buf->pointer-buf->buffer)); buf->pointer += strlen(buf->pointer); } // define some start values. startx = buf->pointer; length = emsg->Length-emsg->SkipFront-emsg->SkipBack; lastpos = emsg->SkipFront; if((styles || colors) && (hookType == MUIV_TextEditor_ExportHook_EMail || hookType == MUIV_TextEditor_ExportHook_Plain)) { UWORD pos; WORD style; BOOL coloured = FALSE; UWORD colour_state = 7; while(length > 0 && ((styles && *styles != 0xffff) || (colors && *colors != 0xffff))) { BOOL color; LONG len; if(colors == NULL || (styles && (coloured ? *styles < *colors : *styles <= *colors))) { pos = *styles++ - 1; style = *styles++; color = FALSE; } else { pos = *colors++ - 1; style = *colors++; color = TRUE; } // skip styles&colors which below lastpos if(pos < lastpos) continue; // depending on how much we export // we have to fire up the style convert routines. if(pos-lastpos <= length) { len = pos-lastpos; memcpy(buf->pointer, emsg->Contents+lastpos, len); buf->pointer += len; if(hookType == MUIV_TextEditor_ExportHook_EMail) { if(color) { if((coloured = (style == colour_state ? TRUE : FALSE))) { *buf->pointer++ = '#'; colour_state ^= 7; } } else { switch(style) { case UNDERLINE: case ~UNDERLINE: { *buf->pointer++ = '_'; } break; case BOLD: case ~BOLD: { *buf->pointer++ = '*'; } break; case ITALIC: case ~ITALIC: { *buf->pointer++ = '/'; } break; } } } else if(hookType == MUIV_TextEditor_ExportHook_Plain) { if(color) { snprintf(buf->pointer, buf->size-(buf->pointer-buf->buffer), "\033p[%d]", style); buf->pointer += strlen(buf->pointer); } else { switch(style) { case UNDERLINE: { *buf->pointer++ = '\033'; *buf->pointer++ = 'u'; currentstyle |= UNDERLINE; } break; case BOLD: { *buf->pointer++ = '\033'; *buf->pointer++ = 'b'; currentstyle |= BOLD; } break; case ITALIC: { *buf->pointer++ = '\033'; *buf->pointer++ = 'i'; currentstyle |= ITALIC; } break; case ~UNDERLINE: case ~BOLD: case ~ITALIC: { currentstyle &= style; if(pos+1 != *styles || *(styles+1) < 0x8000) { *buf->pointer++ = '\033'; *buf->pointer++ = 'n'; if(currentstyle & UNDERLINE) { *buf->pointer++ = '\033'; *buf->pointer++ = 'u'; } if(currentstyle & BOLD) { *buf->pointer++ = '\033'; *buf->pointer++ = 'b'; } if(currentstyle & ITALIC) { *buf->pointer++ = '\033'; *buf->pointer++ = 'i'; } } } break; } } } } else { len = length; memcpy(buf->pointer, emsg->Contents+lastpos, len); buf->pointer += len; } length -= len; if(length == -1) length = 0; lastpos = pos; } } if(length > 0) { memcpy(buf->pointer, emsg->Contents+lastpos, length); buf->pointer += length; } // NUL terminate our buffer string *buf->pointer = '\0'; while(emsg->ExportWrap && buf->pointer-startx > (LONG)emsg->ExportWrap) { ULONG max = emsg->ExportWrap+1; if(startx[emsg->ExportWrap] != '\n') { while(--max && *(startx+max) != ' ') ; // empty while } if(max) { *(startx += max) = '\n'; } else { while(++startx < buf->pointer && *(startx) != ' ') ; // empty while if(buf->pointer != startx) { *startx = '\n'; } } } if(emsg->Last) { result = buf->buffer; if(data) { MyFreePooled(data->mypool, buf); } else { FreeVec(buf); } } else { result = (STRPTR)buf; } } RETURN(result); return(result); }