int WDL_CursesEditor::init(const char *fn, const char *init_if_empty) { m_filename.Set(fn); FILE *fh=fopenUTF8(fn,"rt"); if (!fh) { if (init_if_empty) { fh=fopenUTF8(fn,"w+t"); if (fh) { fwrite(init_if_empty,1,strlen(init_if_empty),fh); fseek(fh,0,SEEK_SET); } } if (!fh) { saveUndoState(); m_clean_undopos=m_undoStack_pos; return 1; } } while(!feof(fh)) { char line[4096]; line[0]=0; fgets(line,sizeof(line),fh); if (!line[0]) break; int l=strlen(line); while(l>0 && (line[l-1]=='\r' || line[l-1]=='\n')) { line[l-1]=0; l--; } WDL_FastString *str=new WDL_FastString; char *p=line,*np; while ((np=strstr(p,"\t"))) // this should be optional, perhaps { *np=0; str->Append(p); { int x; for(x=0;x<m_indent_size;x++) str->Append(" "); } p=np+1; } if (p) str->Append(p); m_text.Add(str); } fclose(fh); saveUndoState(); m_clean_undopos=m_undoStack_pos; return 0; }
void GuiTextEditCtrl::onCopy(bool andCut) { // Don't copy/cut password field! if(mPasswordText) return; if (mBlockEnd > 0) { //save the current state saveUndoState(); //copy the text to the clipboard UTF8* clipBuff = mTextBuffer.createSubstring8(mBlockStart, mBlockEnd - mBlockStart); Platform::setClipboard(clipBuff); delete[] clipBuff; //if we pressed the cut shortcut, we need to cut the selected text from the control... if (andCut) { mTextBuffer.cut(mBlockStart, mBlockEnd - mBlockStart); mCursorPos = mBlockStart; } mBlockStart = 0; mBlockEnd = 0; } }
void GuiTextEditCtrl::onPaste() { //first, make sure there's something in the clipboard to copy... const UTF8 *clipboard = Platform::getClipboard(); if(dStrlen(clipboard) <= 0) return; //save the current state saveUndoState(); //delete anything hilited if (mBlockEnd > 0) { mTextBuffer.cut(mBlockStart, mBlockEnd - mBlockStart); mCursorPos = mBlockStart; mBlockStart = 0; mBlockEnd = 0; } // We'll be converting to UTF16, and maybe trimming the string, // so let's use a StringBuffer, for convinience. StringBuffer pasteText(clipboard); // Space left after we remove the highlighted text S32 stringLen = mTextBuffer.length(); // Trim down to fit in a buffer of size mMaxStrLen S32 pasteLen = pasteText.length(); if(stringLen + pasteLen > mMaxStrLen) { pasteLen = mMaxStrLen - stringLen; pasteText.cut(pasteLen, pasteText.length() - pasteLen); } if (mCursorPos == stringLen) { mTextBuffer.append(pasteText); } else { mTextBuffer.insert(mCursorPos, pasteText); } mCursorPos += pasteLen; }
void DiagramScene::setLineColor(const QColor &color) { myLineColor = color; //Lists of items QList<Arrow *> Arrows; QList<lineItem *> lineItems; foreach(QGraphicsItem *item, selectedItems()){ if(item->type() == lineItem::Type) lineItems.append(qgraphicsitem_cast<lineItem *>(item)); else if(item->type() == Arrow::Type) Arrows.append(qgraphicsitem_cast<Arrow *>(item)); } foreach(Arrow *arrow, Arrows){ saveUndoState(); arrow->setColor(myLineColor); }
bool GuiTextEditCtrl::onKeyDown(const GuiEvent &event) { if ( !isActive() || !isAwake() ) return false; S32 stringLen = mTextBuffer.length(); setUpdate(); // Ugly, but now I'm cool like MarkF. if(event.keyCode == KEY_BACKSPACE) goto dealWithBackspace; if ( event.modifier & SI_SHIFT ) { // Added support for word jump selection. if ( event.modifier & SI_CTRL ) { switch ( event.keyCode ) { case KEY_LEFT: { S32 newpos = findPrevWord(); if ( mBlockStart == mBlockEnd ) { // There was not already a selection so start a new one. mBlockStart = newpos; mBlockEnd = mCursorPos; } else { // There was a selection already... // In this case the cursor MUST be at either the // start or end of that selection. if ( mCursorPos == mBlockStart ) { // We are at the start block and traveling left so // just extend the start block farther left. mBlockStart = newpos; } else { // We are at the end block BUT traveling left // back towards the start block... if ( newpos > mBlockStart ) { // We haven't overpassed the existing start block // so just trim back the end block. mBlockEnd = newpos; } else if ( newpos == mBlockStart ) { // We are back at the start, so no more selection. mBlockEnd = mBlockStart = 0; } else { // Only other option, we just backtracked PAST // our original start block. // So the new position becomes the start block // and the old start block becomes the end block. mBlockEnd = mBlockStart; mBlockStart = newpos; } } } mCursorPos = newpos; return true; } case KEY_RIGHT: { S32 newpos = findNextWord(); if ( mBlockStart == mBlockEnd ) { // There was not already a selection so start a new one. mBlockStart = mCursorPos; mBlockEnd = newpos; } else { // There was a selection already... // In this case the cursor MUST be at either the // start or end of that selection. if ( mCursorPos == mBlockEnd ) { // We are at the end block and traveling right so // just extend the end block farther right. mBlockEnd = newpos; } else { // We are at the start block BUT traveling right // back towards the end block... if ( newpos < mBlockEnd ) { // We haven't overpassed the existing end block // so just trim back the start block. mBlockStart = newpos; } else if ( newpos == mBlockEnd ) { // We are back at the end, so no more selection. mBlockEnd = mBlockStart = 0; } else { // Only other option, we just backtracked PAST // our original end block. // So the new position becomes the end block // and the old end block becomes the start block. mBlockStart = mBlockEnd; mBlockEnd = newpos; } } } mCursorPos = newpos; return true; } default: break; } } // End support for word jump selection. switch ( event.keyCode ) { case KEY_TAB: if ( mTabComplete ) { onTabComplete_callback("1"); return true; } break; // We don't want to fall through if we don't handle the TAB here. case KEY_HOME: mBlockStart = 0; mBlockEnd = mCursorPos; mCursorPos = 0; return true; case KEY_END: mBlockStart = mCursorPos; mBlockEnd = stringLen; mCursorPos = stringLen; return true; case KEY_LEFT: if ((mCursorPos > 0) & (stringLen > 0)) { //if we already have a selected block if (mCursorPos == mBlockEnd) { mCursorPos--; mBlockEnd--; if (mBlockEnd == mBlockStart) { mBlockStart = 0; mBlockEnd = 0; } } else { mCursorPos--; mBlockStart = mCursorPos; if (mBlockEnd == 0) { mBlockEnd = mCursorPos + 1; } } } return true; case KEY_RIGHT: if (mCursorPos < stringLen) { if ((mCursorPos == mBlockStart) && (mBlockEnd > 0)) { mCursorPos++; mBlockStart++; if (mBlockStart == mBlockEnd) { mBlockStart = 0; mBlockEnd = 0; } } else { if (mBlockEnd == 0) { mBlockStart = mCursorPos; mBlockEnd = mCursorPos; } mCursorPos++; mBlockEnd++; } } return true; case KEY_RETURN: case KEY_NUMPADENTER: return dealWithEnter(false); default: break; } } else if (event.modifier & SI_CTRL) { switch(event.keyCode) { #if defined(TORQUE_OS_MAC) // Added UNIX emacs key bindings - just a little hack here... // Ctrl-B - move one character back case KEY_B: { GuiEvent new_event; new_event.modifier = 0; new_event.keyCode = KEY_LEFT; return(onKeyDown(new_event)); } // Ctrl-F - move one character forward case KEY_F: { GuiEvent new_event; new_event.modifier = 0; new_event.keyCode = KEY_RIGHT; return(onKeyDown(new_event)); } // Ctrl-A - move to the beginning of the line case KEY_A: { GuiEvent new_event; new_event.modifier = 0; new_event.keyCode = KEY_HOME; return(onKeyDown(new_event)); } // Ctrl-E - move to the end of the line case KEY_E: { GuiEvent new_event; new_event.modifier = 0; new_event.keyCode = KEY_END; return(onKeyDown(new_event)); } // Ctrl-P - move backward in history case KEY_P: { GuiEvent new_event; new_event.modifier = 0; new_event.keyCode = KEY_UP; return(onKeyDown(new_event)); } // Ctrl-N - move forward in history case KEY_N: { GuiEvent new_event; new_event.modifier = 0; new_event.keyCode = KEY_DOWN; return(onKeyDown(new_event)); } // Ctrl-D - delete under cursor case KEY_D: { GuiEvent new_event; new_event.modifier = 0; new_event.keyCode = KEY_DELETE; return(onKeyDown(new_event)); } case KEY_U: { GuiEvent new_event; new_event.modifier = SI_CTRL; new_event.keyCode = KEY_DELETE; return(onKeyDown(new_event)); } // End added UNIX emacs key bindings #endif // Adding word jump navigation. case KEY_LEFT: { mCursorPos = findPrevWord(); mBlockStart = 0; mBlockEnd = 0; return true; } case KEY_RIGHT: { mCursorPos = findNextWord(); mBlockStart = 0; mBlockEnd = 0; return true; } #if !defined(TORQUE_OS_MAC) // Select all case KEY_A: { selectAllText(); return true; } // windows style cut / copy / paste / undo keybinds case KEY_C: case KEY_X: { // copy, and cut the text if we hit ctrl-x onCopy( event.keyCode==KEY_X ); return true; } case KEY_V: { onPaste(); // Execute the console command! execConsoleCallback(); return true; } case KEY_Z: if (! mDragHit) { onUndo(); return true; } #endif case KEY_DELETE: case KEY_BACKSPACE: //save the current state saveUndoState(); //delete everything in the field mTextBuffer.set(""); mCursorPos = 0; mBlockStart = 0; mBlockEnd = 0; execConsoleCallback(); onChangeCursorPos(); //.logicking return true; default: break; } } #if defined(TORQUE_OS_MAC) // mac style cut / copy / paste / undo keybinds else if (event.modifier & SI_ALT) { // Mac command key maps to alt in torque. // Added Mac cut/copy/paste/undo keys switch(event.keyCode) { // Select all case KEY_A: { selectAllText(); return true; } case KEY_C: case KEY_X: { // copy, and cut the text if we hit cmd-x onCopy( event.keyCode==KEY_X ); return true; } case KEY_V: { onPaste(); // Execute the console command! execConsoleCallback(); return true; } case KEY_Z: if (! mDragHit) { onUndo(); return true; } default: break; } } #endif else { switch(event.keyCode) { case KEY_ESCAPE: if( mEscapeCommand.isNotEmpty() ) { evaluate( mEscapeCommand ); return( true ); } return( Parent::onKeyDown( event ) ); case KEY_RETURN: case KEY_NUMPADENTER: return dealWithEnter(true); case KEY_UP: { if( mHistorySize > 0 ) { if(mHistoryDirty) { updateHistory(&mTextBuffer, false); mHistoryDirty = false; } mHistoryIndex--; if(mHistoryIndex >= 0 && mHistoryIndex <= mHistoryLast) setText(mHistoryBuf[mHistoryIndex]); else if(mHistoryIndex < 0) mHistoryIndex = 0; } return true; } case KEY_DOWN: { if( mHistorySize > 0 ) { if(mHistoryDirty) { updateHistory(&mTextBuffer, false); mHistoryDirty = false; } mHistoryIndex++; if(mHistoryIndex > mHistoryLast) { mHistoryIndex = mHistoryLast + 1; setText(""); } else setText(mHistoryBuf[mHistoryIndex]); } return true; } case KEY_LEFT: // If we have a selection put the cursor to the left side of it. if ( mBlockStart != mBlockEnd ) { mCursorPos = mBlockStart; mBlockStart = mBlockEnd = 0; } else { mBlockStart = mBlockEnd = 0; mCursorPos = getMax( mCursorPos - 1, 0 ); } return true; case KEY_RIGHT: // If we have a selection put the cursor to the right side of it. if ( mBlockStart != mBlockEnd ) { mCursorPos = mBlockEnd; mBlockStart = mBlockEnd = 0; } else { mBlockStart = mBlockEnd = 0; mCursorPos = getMin( mCursorPos + 1, stringLen ); } return true; case KEY_BACKSPACE: dealWithBackspace: //save the current state saveUndoState(); if (mBlockEnd > 0) { mTextBuffer.cut(mBlockStart, mBlockEnd-mBlockStart); mCursorPos = mBlockStart; mBlockStart = 0; mBlockEnd = 0; mHistoryDirty = true; // Execute the console command! execConsoleCallback(); } else if (mCursorPos > 0) { mTextBuffer.cut(mCursorPos-1, 1); mCursorPos--; mHistoryDirty = true; // Execute the console command! execConsoleCallback(); } return true; case KEY_DELETE: //save the current state saveUndoState(); if (mBlockEnd > 0) { mHistoryDirty = true; mTextBuffer.cut(mBlockStart, mBlockEnd-mBlockStart); mCursorPos = mBlockStart; mBlockStart = 0; mBlockEnd = 0; // Execute the console command! execConsoleCallback(); } else if (mCursorPos < stringLen) { mHistoryDirty = true; mTextBuffer.cut(mCursorPos, 1); // Execute the console command! execConsoleCallback(); } return true; case KEY_INSERT: mInsertOn = !mInsertOn; return true; case KEY_HOME: mBlockStart = 0; mBlockEnd = 0; mCursorPos = 0; return true; case KEY_END: mBlockStart = 0; mBlockEnd = 0; mCursorPos = stringLen; return true; default: break; } } switch ( event.keyCode ) { case KEY_TAB: if ( mTabComplete ) { onTabComplete_callback("0"); return( true ); } case KEY_UP: case KEY_DOWN: case KEY_ESCAPE: return Parent::onKeyDown( event ); default: break; } // Handle character input events. if( mProfile->mFont->isValidChar( event.ascii ) ) { handleCharInput( event.ascii ); return true; } // Or eat it if that's appropriate. if( mSinkAllKeyEvents ) return true; // Not handled - pass the event to it's parent. return Parent::onKeyDown( event ); }
void GuiTextEditCtrl::handleCharInput( U16 ascii ) { S32 stringLen = mTextBuffer.length(); // Get the character ready to add to a UTF8 string. UTF16 convertedChar[2] = { ascii, 0 }; //see if it's a number field if ( mProfile->mNumbersOnly ) { if ( ascii == '-') { //a minus sign only exists at the beginning, and only a single minus sign if ( mCursorPos != 0 && !isAllTextSelected() ) { playDeniedSound(); return; } if ( mInsertOn && ( mTextBuffer.getChar(0) == '-' ) ) { playDeniedSound(); return; } } // BJTODO: This is probably not unicode safe. else if ( ascii != '.' && (ascii < '0' || ascii > '9') ) { playDeniedSound(); return; } } //save the current state saveUndoState(); bool alreadyCut = false; //delete anything highlighted if ( mBlockEnd > 0 ) { mTextBuffer.cut(mBlockStart, mBlockEnd-mBlockStart); mCursorPos = mBlockStart; mBlockStart = 0; mBlockEnd = 0; // We just changed the string length! // Get its new value. stringLen = mTextBuffer.length(); // If we already had text highlighted, we just want to cut that text. // Don't cut the next character even if insert is not on. alreadyCut = true; } if ( ( mInsertOn && ( stringLen < mMaxStrLen ) ) || ( !mInsertOn && ( mCursorPos < mMaxStrLen ) ) ) { if ( mCursorPos == stringLen ) { mTextBuffer.append(convertedChar); mCursorPos++; } else { if ( mInsertOn || alreadyCut ) { mTextBuffer.insert(mCursorPos, convertedChar); mCursorPos++; } else { mTextBuffer.cut(mCursorPos, 1); mTextBuffer.insert(mCursorPos, convertedChar); mCursorPos++; } } } else playDeniedSound(); //reset the history index mHistoryDirty = true; //execute the console command if it exists execConsoleCallback(); }
int WDL_CursesEditor::onChar(int c) { if (m_state == -3 || m_state == -4) { switch (c) { case '\r': case '\n': m_state=0; runSearch(); break; case 27: m_state=0; draw(); setCursor(); draw_message("Find cancelled."); break; case KEY_BACKSPACE: if (s_search_string[0]) s_search_string[strlen(s_search_string)-1]=0; m_state=-4; break; default: if (VALIDATE_TEXT_CHAR(c)) { int l=m_state == -3 ? 0 : strlen(s_search_string); m_state = -4; if (l < (int)sizeof(s_search_string)-1) { s_search_string[l]=c; s_search_string[l+1]=0; } } break; } if (m_state) { attrset(m_color_message); bkgdset(m_color_message); mvaddstr(LINES-1,29,s_search_string); clrtoeol(); attrset(0); bkgdset(0); } return 0; } if (c==KEY_DOWN || c==KEY_UP || c==KEY_PPAGE||c==KEY_NPAGE || c==KEY_RIGHT||c==KEY_LEFT||c==KEY_HOME||c==KEY_END) { if (SHIFT_KEY_DOWN) { if (!m_selecting) { m_select_x2=m_select_x1=m_curs_x; m_select_y2=m_select_y1=m_curs_y; m_selecting=1; } } else if (m_selecting) { m_selecting=0; draw(); } } switch(c) { case 'O'-'A'+1: if (!SHIFT_KEY_DOWN && !ALT_KEY_DOWN) { if (m_pane_div <= 0.0 || m_pane_div >= 1.0) { onChar('P'-'A'+1); } if (m_pane_div > 0.0 && m_pane_div < 1.0) { m_curpane=!m_curpane; draw(); draw_status_state(); int paney[2], paneh[2]; GetPaneDims(paney, paneh); if (m_curs_y-m_paneoffs_y[m_curpane] < 0) m_curs_y=m_paneoffs_y[m_curpane]; else if (m_curs_y-m_paneoffs_y[m_curpane] >= paneh[m_curpane]) m_curs_y=paneh[m_curpane]+m_paneoffs_y[m_curpane]-1; setCursor(); } } break; case 'P'-'A'+1: if (!SHIFT_KEY_DOWN && !ALT_KEY_DOWN) { if (m_pane_div <= 0.0 || m_pane_div >= 1.0) { m_pane_div=0.5; m_paneoffs_y[1]=m_paneoffs_y[0]; } else { m_pane_div=1.0; if (m_curpane) m_paneoffs_y[0]=m_paneoffs_y[1]; m_curpane=0; } draw(); draw_status_state(); int paney[2], paneh[2]; const int pane_divy=GetPaneDims(paney, paneh); setCursor(); } break; case 407: case 'Z'-'A'+1: if (!SHIFT_KEY_DOWN && !ALT_KEY_DOWN) { if (m_undoStack_pos > 0) { m_undoStack_pos--; loadUndoState(m_undoStack.Get(m_undoStack_pos)); draw(); setCursor(); char buf[512]; snprintf(buf,sizeof(buf),"Undid action - %d items in undo buffer",m_undoStack_pos); draw_message(buf); } else { draw_message("Can't Undo"); } break; } // fall through case 'Y'-'A'+1: if ((c == 'Z'-'A'+1 || !SHIFT_KEY_DOWN) && !ALT_KEY_DOWN) { if (m_undoStack_pos < m_undoStack.GetSize()-1) { m_undoStack_pos++; loadUndoState(m_undoStack.Get(m_undoStack_pos)); draw(); setCursor(); char buf[512]; snprintf(buf,sizeof(buf),"Redid action - %d items in redo buffer",m_undoStack.GetSize()-m_undoStack_pos-1); draw_message(buf); } else { draw_message("Can't Redo"); } } break; case KEY_IC: if (!SHIFT_KEY_DOWN && !ALT_KEY_DOWN) { s_overwrite=!s_overwrite; setCursor(); break; } // fqll through case 'V'-'A'+1: if (!SHIFT_KEY_DOWN && !ALT_KEY_DOWN) { // generate a m_clipboard using win32 clipboard data WDL_PtrList<const char> lines; WDL_String buf; #ifdef WDL_IS_FAKE_CURSES if (CURSES_INSTANCE) { OpenClipboard(CURSES_INSTANCE->m_hwnd); HANDLE h=GetClipboardData(CF_TEXT); if (h) { char *t=(char *)GlobalLock(h); int s=GlobalSize(h); buf.Set(t,s); GlobalUnlock(t); } CloseClipboard(); } else #endif { buf.Set(s_fake_clipboard.Get()); } if (buf.Get() && buf.Get()[0]) { char *src=buf.Get(); while (*src) { char *seek=src; while (*seek && *seek != '\r' && *seek != '\n') seek++; char hadclr=*seek; if (*seek) *seek++=0; lines.Add(src); if (hadclr == '\r' && *seek == '\n') seek++; if (hadclr && !*seek) { lines.Add(""); } src=seek; } } if (lines.GetSize()) { removeSelect(); // insert lines at m_curs_y,m_curs_x if (m_curs_y >= m_text.GetSize()) m_curs_y=m_text.GetSize()-1; if (m_curs_y < 0) m_curs_y=0; preSaveUndoState(); WDL_FastString poststr; int x; int indent_to_pos = -1; for (x = 0; x < lines.GetSize(); x ++) { WDL_FastString *str=m_text.Get(m_curs_y); const char *tstr=lines.Get(x); if (!tstr) tstr=""; if (!x) { if (str) { if (m_curs_x < 0) m_curs_x=0; int tmp=str->GetLength(); if (m_curs_x > tmp) m_curs_x=tmp; poststr.Set(str->Get()+m_curs_x); str->SetLen(m_curs_x); const char *p = str->Get(); while (*p == ' ' || *p == '\t') p++; if (!*p && p > str->Get()) { if (lines.GetSize()>1) { while (*tstr == ' ' || *tstr == '\t') tstr++; } indent_to_pos = m_curs_x; } str->Append(tstr); } else { m_text.Insert(m_curs_y,(str=new WDL_FastString(tstr))); } if (lines.GetSize() > 1) { m_curs_y++; } else { m_curs_x = str->GetLength(); str->Append(poststr.Get()); } } else if (x == lines.GetSize()-1) { WDL_FastString *s=newIndentedFastString(tstr,indent_to_pos); m_curs_x = s->GetLength(); s->Append(poststr.Get()); m_text.Insert(m_curs_y,s); } else { m_text.Insert(m_curs_y,newIndentedFastString(tstr,indent_to_pos)); m_curs_y++; } } draw(); setCursor(); draw_message("Pasted"); saveUndoState(); } else { setCursor(); draw_message("Clipboard empty"); } } break; case KEY_DC: if (!SHIFT_KEY_DOWN && !ALT_KEY_DOWN) { WDL_FastString *s; if (m_selecting) { preSaveUndoState(); removeSelect(); draw(); saveUndoState(); setCursor(); } else if ((s=m_text.Get(m_curs_y))) { if (m_curs_x < s->GetLength()) { preSaveUndoState(); bool hadCom = LineCanAffectOtherLines(s->Get(),m_curs_x,1); s->DeleteSub(m_curs_x,1); if (!hadCom) hadCom = LineCanAffectOtherLines(s->Get(),-1,-1); draw(hadCom ? -1 : m_curs_y); saveUndoState(); setCursor(); } else // append next line to us { if (m_curs_y < m_text.GetSize()-1) { preSaveUndoState(); WDL_FastString *nl=m_text.Get(m_curs_y+1); if (nl) { s->Append(nl->Get()); } m_text.Delete(m_curs_y+1,true); draw(); saveUndoState(); setCursor(); } } } break; } case 'C'-'A'+1: case 'X'-'A'+1: if (!SHIFT_KEY_DOWN && !ALT_KEY_DOWN && m_selecting) { if (c!= 'C'-'A'+1) m_selecting=0; int miny,maxy,minx,maxx; int x; getselectregion(minx,miny,maxx,maxy); const char *status=""; char statusbuf[512]; if (minx != maxx|| miny != maxy) { int bytescopied=0; s_fake_clipboard.Set(""); int lht=0,fht=0; if (c != 'C'-'A'+1) preSaveUndoState(); for (x = miny; x <= maxy; x ++) { WDL_FastString *s=m_text.Get(x); if (s) { const char *str=s->Get(); int sx,ex; if (x == miny) sx=max(minx,0); else sx=0; int tmp=s->GetLength(); if (sx > tmp) sx=tmp; if (x == maxy) ex=min(maxx,tmp); else ex=tmp; bytescopied += ex-sx + (x!=maxy); if (s_fake_clipboard.Get() && s_fake_clipboard.Get()[0]) s_fake_clipboard.Append("\r\n"); s_fake_clipboard.Append(ex-sx?str+sx:"",ex-sx); if (c != 'C'-'A'+1) { if (sx == 0 && ex == tmp) // remove entire line { m_text.Delete(x,true); if (x==miny) miny--; x--; maxy--; } else { if (x==miny) fht=1; if (x == maxy) lht=1; s->DeleteSub(sx,ex-sx); } } } } if (fht && lht && miny+1 == maxy) { m_text.Get(miny)->Append(m_text.Get(maxy)->Get()); m_text.Delete(maxy,true); } if (c != 'C'-'A'+1) { m_curs_y=miny; if (m_curs_y < 0) m_curs_y=0; m_curs_x=minx; saveUndoState(); snprintf(statusbuf,sizeof(statusbuf),"Cut %d bytes",bytescopied); } else snprintf(statusbuf,sizeof(statusbuf),"Copied %d bytes",bytescopied); #ifdef WDL_IS_FAKE_CURSES if (CURSES_INSTANCE) { int l=s_fake_clipboard.GetLength()+1; HANDLE h=GlobalAlloc(GMEM_MOVEABLE,l); void *t=GlobalLock(h); memcpy(t,s_fake_clipboard.Get(),l); GlobalUnlock(h); OpenClipboard(CURSES_INSTANCE->m_hwnd); EmptyClipboard(); SetClipboardData(CF_TEXT,h); CloseClipboard(); } #endif status=statusbuf; } else status="No selection"; draw(); setCursor(); draw_message(status); } break; case 'A'-'A'+1: if (!SHIFT_KEY_DOWN && !ALT_KEY_DOWN) { m_selecting=1; m_select_x1=0; m_select_y1=0; m_select_y2=m_text.GetSize()-1; m_select_x2=0; if (m_text.Get(m_select_y2)) m_select_x2=m_text.Get(m_select_y2)->GetLength(); draw(); setCursor(); } break; case 27: if (!SHIFT_KEY_DOWN && !ALT_KEY_DOWN && m_selecting) { m_selecting=0; draw(); setCursor(); break; } break; case KEY_F3: case 'G'-'A'+1: if (!SHIFT_KEY_DOWN && !ALT_KEY_DOWN && s_search_string[0]) { runSearch(); return 0; } // fall through case 'F'-'A'+1: if (!SHIFT_KEY_DOWN && !ALT_KEY_DOWN) { draw_message(""); attrset(m_color_message); bkgdset(m_color_message); mvaddstr(LINES-1,0,"Find string (ESC to cancel): "); if (m_selecting && m_select_y1==m_select_y2) { WDL_FastString* s=m_text.Get(m_select_y1); if (s) { const char* p=s->Get(); int xlo=min(m_select_x1, m_select_x2); int xhi=max(m_select_x1, m_select_x2); int i; for (i=xlo; i < xhi; ++i) { if (!isalnum(p[i]) && p[i] != '_') break; } if (i == xhi && xhi > xlo && xhi-xlo < sizeof(s_search_string)) { lstrcpyn(s_search_string, p+xlo, xhi-xlo+1); } } } addstr(s_search_string); clrtoeol(); attrset(0); bkgdset(0); m_state=-3; // find, initial (m_state=4 when we've typed something) } break; case KEY_DOWN: { if (CTRL_KEY_DOWN) { int paney[2], paneh[2]; GetPaneDims(paney, paneh); int maxscroll=m_text.GetSize()-paneh[m_curpane]+4; if (m_paneoffs_y[m_curpane] < maxscroll-1) { m_paneoffs_y[m_curpane]++; if (m_curs_y < m_paneoffs_y[m_curpane]) m_curs_y=m_paneoffs_y[m_curpane]; draw(); } } else { m_curs_y++; if (m_curs_y>=m_text.GetSize()) m_curs_y=m_text.GetSize()-1; if (m_curs_y < 0) m_curs_y=0; } if (m_selecting) { setCursor(1); m_select_x2=m_curs_x; m_select_y2=m_curs_y; draw(); } setCursor(1); } break; case KEY_UP: { if (CTRL_KEY_DOWN) { if (m_paneoffs_y[m_curpane] > 0) { int paney[2], paneh[2]; GetPaneDims(paney, paneh); m_paneoffs_y[m_curpane]--; if (m_curs_y > m_paneoffs_y[m_curpane]+paneh[m_curpane]-1) m_curs_y = m_paneoffs_y[m_curpane]+paneh[m_curpane]-1; if (m_curs_y < 0) m_curs_y=0; draw(); } } else { if(m_curs_y>0) m_curs_y--; } if (m_selecting) { setCursor(1); m_select_x2=m_curs_x; m_select_y2=m_curs_y; draw(); } setCursor(1); } break; case KEY_PPAGE: { if (m_curs_y > m_paneoffs_y[m_curpane]) { m_curs_y=m_paneoffs_y[m_curpane]; if (m_curs_y < 0) m_curs_y=0; } else { int paney[2], paneh[2]; GetPaneDims(paney, paneh); m_curs_y -= paneh[m_curpane]; if (m_curs_y < 0) m_curs_y=0; m_paneoffs_y[m_curpane]=m_curs_y; } if (m_selecting) { setCursor(1); m_select_x2=m_curs_x; m_select_y2=m_curs_y; } draw(); setCursor(1); } break; case KEY_NPAGE: { int paney[2], paneh[2]; GetPaneDims(paney, paneh); if (m_curs_y >= m_paneoffs_y[m_curpane]+paneh[m_curpane]-1) m_paneoffs_y[m_curpane]=m_curs_y-1; m_curs_y = m_paneoffs_y[m_curpane]+paneh[m_curpane]-1; if (m_curs_y >= m_text.GetSize()) m_curs_y=m_text.GetSize()-1; if (m_curs_y < 0) m_curs_y=0; if (m_selecting) { setCursor(1); m_select_x2=m_curs_x; m_select_y2=m_curs_y; } draw(); setCursor(1); } break; case KEY_RIGHT: { if (1) // wrap across lines { WDL_FastString *s = m_text.Get(m_curs_y); if (s && m_curs_x >= s->GetLength() && m_curs_y < m_text.GetSize()) { m_curs_y++; m_curs_x = -1; } } if(m_curs_x<0) { m_curs_x=0; } else { if (CTRL_KEY_DOWN) { WDL_FastString *s = m_text.Get(m_curs_y); if (!s||m_curs_x >= s->GetLength()) break; int lastType = categorizeCharForWordNess(s->Get()[m_curs_x++]); while (m_curs_x < s->GetLength()) { int thisType = categorizeCharForWordNess(s->Get()[m_curs_x]); if (thisType != lastType && thisType != 0) break; lastType=thisType; m_curs_x++; } } else { m_curs_x++; } } if (m_selecting) { setCursor(); m_select_x2=m_curs_x; m_select_y2=m_curs_y; draw(); } setCursor(); } break; case KEY_LEFT: { bool doMove=true; if (1) // wrap across lines { WDL_FastString *s = m_text.Get(m_curs_y); if (s && m_curs_y>0 && m_curs_x == 0) { s = m_text.Get(--m_curs_y); if (s) { m_curs_x = s->GetLength(); doMove=false; } } } if(m_curs_x>0 && doMove) { if (CTRL_KEY_DOWN) { WDL_FastString *s = m_text.Get(m_curs_y); if (!s) break; if (m_curs_x > s->GetLength()) m_curs_x = s->GetLength(); m_curs_x--; int lastType = categorizeCharForWordNess(s->Get()[m_curs_x--]); while (m_curs_x >= 0) { int thisType = categorizeCharForWordNess(s->Get()[m_curs_x]); if (thisType != lastType && lastType != 0) break; lastType=thisType; m_curs_x--; } m_curs_x++; } else { m_curs_x--; } } if (m_selecting) { setCursor(); m_select_x2=m_curs_x; m_select_y2=m_curs_y; draw(); } setCursor(); } break; case KEY_HOME: { m_curs_x=0; if (CTRL_KEY_DOWN) m_curs_y=0; if (m_selecting) { setCursor(); m_select_x2=m_curs_x; m_select_y2=m_curs_y; draw(); } setCursor(); } break; case KEY_END: { if (m_text.Get(m_curs_y)) m_curs_x=m_text.Get(m_curs_y)->GetLength(); if (CTRL_KEY_DOWN) m_curs_y=m_text.GetSize(); if (m_selecting) { setCursor(); m_select_x2=m_curs_x; m_select_y2=m_curs_y; draw(); } setCursor(); } break; case KEY_BACKSPACE: // backspace, baby if (m_selecting) { preSaveUndoState(); removeSelect(); draw(); saveUndoState(); setCursor(); } else if (m_curs_x > 0) { WDL_FastString *tl=m_text.Get(m_curs_y); if (tl) { preSaveUndoState(); bool hadCom = LineCanAffectOtherLines(tl->Get(), m_curs_x-1,1); tl->DeleteSub(--m_curs_x,1); if (!hadCom) hadCom = LineCanAffectOtherLines(tl->Get(),-1,-1); draw(hadCom?-1:m_curs_y); saveUndoState(); setCursor(); } } else // append current line to previous line { WDL_FastString *fl=m_text.Get(m_curs_y-1), *tl=m_text.Get(m_curs_y); if (!tl) { m_curs_y--; if (fl) m_curs_x=fl->GetLength(); draw(); saveUndoState(); setCursor(); } else if (fl) { preSaveUndoState(); m_curs_x=fl->GetLength(); fl->Append(tl->Get()); m_text.Delete(m_curs_y--,true); draw(); saveUndoState(); setCursor(); } } break; case 'L'-'A'+1: if (!SHIFT_KEY_DOWN && !ALT_KEY_DOWN) { draw(); setCursor(); } break; case 13: //KEY_ENTER: //insert newline preSaveUndoState(); if (m_selecting) { removeSelect(); draw(); setCursor(); } if (m_curs_y >= m_text.GetSize()) { m_curs_y=m_text.GetSize(); m_text.Add(new WDL_FastString); } if (s_overwrite) { WDL_FastString *s = m_text.Get(m_curs_y); int plen=0; const char *pb=NULL; if (s) { pb = s->Get(); while (plen < m_curs_x && (pb[plen]== ' ' || pb[plen] == '\t')) plen++; } if (++m_curs_y >= m_text.GetSize()) { m_curs_y = m_text.GetSize(); WDL_FastString *ns=new WDL_FastString; if (plen>0) ns->Set(pb,plen); m_text.Insert(m_curs_y,ns); } s = m_text.Get(m_curs_y); if (s && plen > s->GetLength()) plen=s->GetLength(); m_curs_x=plen; } else { WDL_FastString *s = m_text.Get(m_curs_y); if (s) { if (m_curs_x > s->GetLength()) m_curs_x = s->GetLength(); WDL_FastString *nl = new WDL_FastString(); int plen=0; const char *pb = s->Get(); while (plen < m_curs_x && (pb[plen]== ' ' || pb[plen] == '\t')) plen++; if (plen>0) nl->Set(pb,plen); nl->Append(pb+m_curs_x); m_text.Insert(++m_curs_y,nl); s->SetLen(m_curs_x); m_curs_x=plen; } } m_offs_x=0; draw(); saveUndoState(); setCursor(); break; case '\t': if (m_selecting) { preSaveUndoState(); bool isRev = !!(GetAsyncKeyState(VK_SHIFT)&0x8000); indentSelect(isRev?-m_indent_size:m_indent_size); // indent selection: draw(); setCursor(); saveUndoState(); break; } default: //insert char if(VALIDATE_TEXT_CHAR(c)) { preSaveUndoState(); if (m_selecting) { removeSelect(); draw(); setCursor(); } if (!m_text.Get(m_curs_y)) m_text.Insert(m_curs_y,new WDL_FastString); WDL_FastString *ss; if ((ss=m_text.Get(m_curs_y))) { char str[64]; int slen ; if (c == '\t') { slen = min(m_indent_size,64); if (slen<1) slen=1; int x; for(x=0;x<slen;x++) str[x]=' '; } else { str[0]=c; slen = 1; } bool hadCom = LineCanAffectOtherLines(ss->Get(),-1,-1); if (s_overwrite) { if (!hadCom) hadCom = LineCanAffectOtherLines(ss->Get(),m_curs_x,slen); ss->DeleteSub(m_curs_x,slen); } ss->Insert(str,m_curs_x,slen); if (!hadCom) hadCom = LineCanAffectOtherLines(ss->Get(),m_curs_x,slen); m_curs_x += slen; draw(hadCom ? -1 : m_curs_y); } saveUndoState(); setCursor(); } break; } return 0; }
void TextEdit::onKeyDown(const Event &event) { int stringLen = strlen(text); setUpdate(); if (event.modifier & SI_SHIFT) { switch(event.diKeyCode) { case DIK_HOME: blockStart = 0; blockEnd = cursorPos; cursorPos = 0; return; case DIK_END: blockStart = cursorPos; blockEnd = stringLen; cursorPos = stringLen; return; case DIK_LEFT: if ((cursorPos > 0) & (stringLen > 0)) { //if we already have a selected block if (cursorPos == blockEnd) { cursorPos--; blockEnd--; if (blockEnd == blockStart) { blockStart = 0; blockEnd = 0; } } else { cursorPos--; blockStart = cursorPos; if (blockEnd == 0) { blockEnd = cursorPos + 1; } } } return; case DIK_RIGHT: if (cursorPos < stringLen) { if ((cursorPos == blockStart) && (blockEnd > 0)) { cursorPos++; blockStart++; if (blockStart == blockEnd) { blockStart = 0; blockEnd = 0; } } else { if (blockEnd == 0) { blockStart = cursorPos; blockEnd = cursorPos; } cursorPos++; blockEnd++; } } return; } } else if (event.modifier & SI_CTRL) { switch(event.diKeyCode) { case DIK_C: case DIK_X: if (blockEnd > 0) { //save the current state saveUndoState(); char buf[SimpleText::MAX_STRING_LENGTH + 1], temp; //copy to the clipboard if (!OpenClipboard(getCanvas()->getHandle())) return; LPTSTR lptstrCopy; HGLOBAL hglbCopy; hglbCopy = GlobalAlloc(GMEM_DDESHARE, (blockEnd - blockStart + 1)); if (hglbCopy == NULL) { CloseClipboard(); return; } // Lock the handle and copy the text to the buffer. temp = text[blockEnd]; text[blockEnd] = '\0'; lptstrCopy = (char*)(GlobalLock(hglbCopy)); strcpy(lptstrCopy, &text[blockStart]); text[blockEnd] = temp; GlobalUnlock(hglbCopy); // Place the handle on the clipboard. SetClipboardData(CF_TEXT, hglbCopy); CloseClipboard(); if (event.diKeyCode == DIK_X) { strcpy(buf, &text[blockEnd]); cursorPos = blockStart; strcpy(&text[blockStart], buf); } blockStart = 0; blockEnd = 0; } return; case DIK_V: char buf[SimpleText::MAX_STRING_LENGTH + 1]; //delete anything hilited if (blockEnd > 0) { //save the current state saveUndoState(); strcpy(buf, &text[blockEnd]); cursorPos = blockStart; strcpy(&text[blockStart], buf); blockStart = 0; blockEnd = 0; } HGLOBAL hglb; LPTSTR lptstr; if (!IsClipboardFormatAvailable(CF_TEXT)) return; if (! OpenClipboard(getCanvas()->getHandle())) return; hglb = GetClipboardData(CF_TEXT); if (hglb != NULL) { lptstr = (char*)GlobalLock(hglb); if (lptstr != NULL) { int pasteLen = strlen(lptstr); if ((stringLen + pasteLen) > maxStrLen) { pasteLen = maxStrLen - stringLen; } if (cursorPos == stringLen) { strncpy(&text[cursorPos], lptstr, pasteLen); text[cursorPos + pasteLen] = '\0'; } else { strcpy(buf, &text[cursorPos]); strncpy(&text[cursorPos],lptstr, pasteLen); strcpy(&text[cursorPos + pasteLen], buf); } cursorPos += pasteLen; GlobalUnlock(hglb); } } CloseClipboard(); return; case DIK_U: if (! dragHit) { char buf[SimpleText::MAX_STRING_LENGTH + 1]; int tempBlockStart; int tempBlockEnd; int tempCursorPos; //save the current strcpy(buf, text); tempBlockStart = blockStart; tempBlockEnd = blockEnd; tempCursorPos = cursorPos; //restore the prev strcpy(text, undoText); blockStart = undoBlockStart; blockEnd = undoBlockEnd; cursorPos = undoCursorPos; //update the undo strcpy(undoText, buf); undoBlockStart = tempBlockStart; undoBlockEnd = tempBlockEnd; undoCursorPos = tempCursorPos; return; } case DIK_DELETE: case DIK_BACK: //save the current state saveUndoState(); //delete everything in the field text[0] = '\0'; cursorPos = 0; blockStart = 0; blockEnd = 0; return; } //switch } else { switch(event.diKeyCode) { case DIK_LEFT: blockStart = 0; blockEnd = 0; if (cursorPos > 0) { cursorPos--; } return; case DIK_RIGHT: blockStart = 0; blockEnd = 0; if (cursorPos < stringLen) { cursorPos++; } return; case DIK_BACK: if (blockEnd > 0) { char buf[SimpleText::MAX_STRING_LENGTH + 1]; strcpy(buf, &text[blockEnd]); cursorPos = blockStart; strcpy(&text[blockStart], buf); blockStart = 0; blockEnd = 0; } else if (cursorPos > 0) { char buf[SimpleText::MAX_STRING_LENGTH + 1]; strcpy(buf, &text[cursorPos]); cursorPos--; strcpy(&text[cursorPos], buf); } return; case DIK_DELETE: //save the current state saveUndoState(); if (blockEnd > 0) { char buf[SimpleText::MAX_STRING_LENGTH + 1]; strcpy(buf, &text[blockEnd]); cursorPos = blockStart; strcpy(&text[blockStart], buf); blockStart = 0; blockEnd = 0; } else if (cursorPos < stringLen) { char buf[SimpleText::MAX_STRING_LENGTH + 1]; strcpy(buf, &text[cursorPos + 1]); strcpy(&text[cursorPos], buf); } return; case DIK_INSERT: insertOn = !insertOn; return; case DIK_HOME: blockStart = 0; blockEnd = 0; cursorPos = 0; return; case DIK_END: blockStart = 0; blockEnd = 0; cursorPos = stringLen; return; } } switch (event.diKeyCode) { case DIK_UP: case DIK_DOWN: case DIK_TAB: case DIK_ESCAPE: Parent::onKeyDown(event); return; } //if ((! mbNumbersOnly && isprint(event.ascii)) || (mbNumbersOnly && event.ascii >= '0' && mbNumbersOnly && event.ascii <= '9')) if (isprint(event.ascii)) { //see if it's a number field if (mbNumbersOnly) { if (event.ascii == '-') { //a minus sign only exists at the beginning, and only a single minus sign if (cursorPos != 0) return; if (insertOn && (text[0] == '-')) return; } else if (event.ascii < '0' || event.ascii > '9') { return; } } //save the current state saveUndoState(); //delete anything hilited if (blockEnd > 0) { char buf[SimpleText::MAX_STRING_LENGTH + 1]; strcpy(buf, &text[blockEnd]); cursorPos = blockStart; strcpy(&text[blockStart], buf); blockStart = 0; blockEnd = 0; } if ((insertOn && (stringLen < maxStrLen)) || ((! insertOn) && (cursorPos < maxStrLen))) { if (cursorPos == stringLen) { text[cursorPos++] = event.ascii; text[cursorPos] = '\0'; } else { if (insertOn) { char buf[SimpleText::MAX_STRING_LENGTH + 1]; strcpy(buf, &text[cursorPos]); text[cursorPos] = event.ascii; cursorPos++; strcpy(&text[cursorPos], buf); } else { text[cursorPos++] = event.ascii; if (cursorPos > stringLen) { text[cursorPos] = '\0'; } } } } return; } }
foreach(lineItem *line, lineItems){ saveUndoState(); line->myOwner()->setColor(myLineColor); }