void WDL_CursesEditor::draw(int lineidx) { attrset(A_NORMAL); if (lineidx >= 0) { int comment_state = GetCommentStateForLineStart(lineidx); WDL_FastString *s=m_text.Get(lineidx); if (s && lineidx >= m_offs_y && lineidx < m_offs_y+getVisibleLines()) { doDrawString(lineidx-m_offs_y+m_top_margin,0,lineidx,s->Get(),COLS,&comment_state, min(s->GetLength(),m_offs_x)); } return; } draw_top_line(); attrset(A_NORMAL); bkgdset(A_NORMAL); move(m_top_margin,0); clrtoeol(); int comment_state = GetCommentStateForLineStart(m_offs_y); const int VISIBLE_LINES = getVisibleLines(); for(int i=0;i<VISIBLE_LINES;i++) { int ln=i+m_offs_y; WDL_FastString *s=m_text.Get(ln); if(!s) { move(i+m_top_margin,0); clrtoeol(); continue; } doDrawString(i+m_top_margin,0,ln,s->Get(),COLS,&comment_state,min(m_offs_x,s->GetLength())); } // move(LINES-2,0); // clrtoeol(); if (m_bottom_margin>0) { attrset(m_color_bottomline); bkgdset(m_color_bottomline); if (m_selecting) { mvaddstr(LINES-1,0,"SELECTING - ESC-cancel, " "Ctrl+C,X,V, etc"); } else { draw_bottom_line(); } clrtoeol(); attrset(0); bkgdset(0); } }
void WDL_CursesEditor::setCursor(int isVscroll) { int maxx=m_text.Get(m_curs_y) ? m_text.Get(m_curs_y)->GetLength() : 0; if (isVscroll) { if (m_want_x >= 0) m_curs_x=m_want_x; } else m_want_x=-1; if(m_curs_x>maxx) { if (isVscroll) m_want_x=m_curs_x; m_curs_x=maxx; } int redraw=0; if (m_curs_x < m_offs_x) { redraw=1; m_offs_x=m_curs_x; } else if (m_curs_x >= m_offs_x + COLS) { m_offs_x = m_curs_x - COLS + 1; redraw=1; } //screen boundary checking if(m_curs_y>=(m_offs_y+getVisibleLines())) { m_offs_y = m_curs_y - getVisibleLines()+1; redraw=1; } if(m_curs_y<m_offs_y) { m_offs_y=m_curs_y; redraw=1; } if(redraw) draw(); draw_status_state(); //put cursor on screen move(m_top_margin+m_curs_y-m_offs_y,m_curs_x-m_offs_x); }
void LLChatEntry::expandText() { S32 line_count = mSingleLineMode ? 1 : mExpandLinesCount; // <FS:Ansariel> Store result of getVisibleLines - it calls reflow //int visible_lines_count = llabs(getVisibleLines(true).first - getVisibleLines(true).second); std::pair<BOOL, BOOL> visible_lines = getVisibleLines(true); int visible_lines_count = llabs(visible_lines.first - visible_lines.second); // </FS:Ansariel> bool can_changed = getLineCount() <= line_count || line_count < mPrevExpandedLineCount ; mPrevExpandedLineCount = line_count; // true if pasted text has more lines than expand height limit and expand limit is not reached yet bool text_pasted = (getLineCount() > line_count) && (visible_lines_count < line_count); if (mIsExpandable && (can_changed || text_pasted || mSingleLineMode) && getLineCount() != mPrevLinesCount) { int lines_height = 0; if (text_pasted) { // text is pasted and now mLineInfoList.size() > mExpandLineCounts and mLineInfoList is not empty, // so lines_height is the sum of the last 'expanded_line_count' lines height lines_height = (mLineInfoList.end() - line_count)->mRect.mTop - mLineInfoList.back().mRect.mBottom; } else { lines_height = mLineInfoList.begin()->mRect.mTop - mLineInfoList.back().mRect.mBottom; } int height = mVPad * 2 + lines_height; LLRect doc_rect = getRect(); doc_rect.setOriginAndSize(doc_rect.mLeft, doc_rect.mBottom, doc_rect.getWidth(), height); setShape(doc_rect); mPrevLinesCount = getLineCount(); if (mTextExpandedSignal) { (*mTextExpandedSignal)(this, LLSD() ); } needsReflow(); } }
void LLExpandableTextBox::LLTextBoxEx::showExpandText() { if (!mExpanderVisible) { // make sure we're scrolled to top when collapsing if (mScroller) { mScroller->goToTop(); } // get fully visible lines std::pair<S32, S32> visible_lines = getVisibleLines(true); S32 last_line = visible_lines.second - 1; LLStyle::Params expander_style(getDefaultStyleParams()); expander_style.font.style = "UNDERLINE"; expander_style.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); LLExpanderSegment* expanderp = new LLExpanderSegment(new LLStyle(expander_style), getLineStart(last_line), getLength() + 1, mExpanderLabel, *this); insertSegment(expanderp); mExpanderVisible = true; } }
void WDL_CursesEditor::draw(int lineidx) { const int VISIBLE_LINES = getVisibleLines(); int paney[2], paneh[2]; const int pane_divy=GetPaneDims(paney, paneh); #ifdef WDL_IS_FAKE_CURSES if (m_cursesCtx) { CURSES_INSTANCE->offs_y[0]=m_paneoffs_y[0]; CURSES_INSTANCE->offs_y[1]=m_paneoffs_y[1]; CURSES_INSTANCE->div_y=pane_divy; CURSES_INSTANCE->tot_y=m_text.GetSize(); CURSES_INSTANCE->scrollbar_topmargin = m_top_margin; CURSES_INSTANCE->scrollbar_botmargin = m_bottom_margin; } #endif attrset(A_NORMAL); if (lineidx >= 0) { int comment_state = GetCommentStateForLineStart(lineidx); WDL_FastString *s=m_text.Get(lineidx); if (s) { int y=lineidx-m_paneoffs_y[0]; if (y >= 0 && y < paneh[0]) { doDrawString(paney[0]+y, 0, lineidx, s->Get(), COLS, &comment_state, min(s->GetLength(), m_offs_x)); } y=lineidx-m_paneoffs_y[1]; if (y >= 0 && y < paneh[1]) { doDrawString(paney[1]+y, 0, lineidx, s->Get(), COLS, &comment_state, min(s->GetLength(), m_offs_x)); } } return; } __curses_invalidatefull((win32CursesCtx*)m_cursesCtx,false); draw_top_line(); attrset(A_NORMAL); bkgdset(A_NORMAL); move(m_top_margin,0); clrtoeol(); int pane, i; for (pane=0; pane < 2; ++pane) { int ln=m_paneoffs_y[pane]; int y=paney[pane]; int h=paneh[pane]; int comment_state=GetCommentStateForLineStart(ln); for(i=0; i < h; ++i, ++ln, ++y) { WDL_FastString *s=m_text.Get(ln); if (!s) { move(y,0); clrtoeol(); } else { doDrawString(y,0,ln,s->Get(),COLS,&comment_state,min(m_offs_x,s->GetLength())); } } } attrset(m_color_bottomline); bkgdset(m_color_bottomline); if (m_bottom_margin>0) { move(LINES-1, 0); #define BOLD(x) { attrset(m_color_bottomline|A_BOLD); addstr(x); attrset(m_color_bottomline&~A_BOLD); } if (m_selecting) { mvaddstr(LINES-1,0,"SELECTING ESC:cancel Ctrl+("); BOLD("C"); addstr("opy "); BOLD("X"); addstr(":cut "); BOLD("V"); addstr(":paste)"); } else { mvaddstr(LINES-1, 0, "Ctrl+("); if (m_pane_div <= 0.0 || m_pane_div >= 1.0) { BOLD("P"); addstr("ane "); } else { BOLD("O"); addstr("therpane "); addstr("no"); BOLD("P"); addstr("anes "); } BOLD("F"); addstr("ind "); addstr("ma"); BOLD("T"); addstr("ch"); draw_bottom_line(); addstr(")"); } #undef BOLD clrtoeol(); } attrset(0); bkgdset(0); __curses_invalidatefull((win32CursesCtx*)m_cursesCtx,true); }
LRESULT WDL_CursesEditor::onMouseMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CAPTURECHANGED: break; case WM_MOUSEMOVE: if (GetCapture()==hwnd && CURSES_INSTANCE->m_font_w && CURSES_INSTANCE->m_font_h) { int x = ((short)LOWORD(lParam)) / CURSES_INSTANCE->m_font_w + m_offs_x; int y = ((short)HIWORD(lParam)) / CURSES_INSTANCE->m_font_h + m_offs_y - m_top_margin; if (!m_selecting && (x != m_curs_x || y != m_curs_y)) { m_select_x2=m_select_x1=m_curs_x; m_select_y2=m_select_y1=m_curs_y; m_selecting=1; } if (m_selecting && (m_select_x2!=x || m_select_y2 != y)) { if (y < m_offs_y && m_offs_y > 0) { m_offs_y--; } else if (y > m_offs_y + getVisibleLines() && m_offs_y + getVisibleLines() < m_text.GetSize()) { m_offs_y++; } if (x < m_offs_x && m_offs_x > 0) { m_offs_x--; } else if (x > m_offs_x+COLS) { int sz=0; int a; const int vl=getVisibleLines(); for (a=0;a<vl;a++) if (m_text.Get(m_offs_y + a) && m_text.Get(m_offs_y + a)->GetLength() > sz) sz=m_text.Get(m_offs_y + a)->GetLength(); if (sz > m_offs_x + COLS - 8) m_offs_x++; } m_select_y2=y; m_select_x2=x; if (m_select_y2<0) m_select_y2=0; else if (m_select_y2>=m_text.GetSize()) { m_select_y2=m_text.GetSize()-1; WDL_FastString *s=m_text.Get(m_select_y2); if (s) m_select_x2 = s->GetLength(); } if (m_select_x2<0)m_select_x2=0; WDL_FastString *s=m_text.Get(m_select_y2); if (s && m_select_x2>s->GetLength()) m_select_x2 = s->GetLength(); draw(); if (m_curs_y >= m_offs_y && m_curs_y < m_offs_y + getVisibleLines()) setCursor(); } } break; case WM_RBUTTONDOWN: case WM_LBUTTONDOWN: if (CURSES_INSTANCE->m_font_w && CURSES_INSTANCE->m_font_h) { if (uMsg == WM_LBUTTONDOWN) m_selecting=0; m_curs_x = m_offs_x + LOWORD(lParam) / CURSES_INSTANCE->m_font_w; int a = HIWORD(lParam)/CURSES_INSTANCE->m_font_h - m_top_margin; if (a>=getVisibleLines()) a=getVisibleLines()-1; if (a<0)a=0; m_curs_y = m_offs_y + a; if (m_curs_y > m_text.GetSize()-1) { m_curs_y = m_text.GetSize()-1; WDL_FastString *s=m_text.Get(m_curs_y); if (s) m_curs_x=s->GetLength(); } if (m_curs_x < 0) m_curs_x = 0; WDL_FastString *s=m_text.Get(m_curs_y); if (s && m_curs_x > s->GetLength()) m_curs_x=s->GetLength(); if (m_curs_y < 0) m_curs_y = 0; draw(); setCursor(); if (uMsg == WM_LBUTTONDOWN) { SetCapture(hwnd); } else { onRightClick(); } } return 0; case WM_LBUTTONUP: ReleaseCapture(); return 0; case WM_MOUSEWHEEL: m_offs_y -= ((short)HIWORD(wParam))/20; if(m_offs_y > m_text.GetSize() - getVisibleLines()) m_offs_y=m_text.GetSize() - getVisibleLines(); if (m_offs_y < 0) m_offs_y=0; draw(); if (m_curs_y >= m_offs_y && m_curs_y < m_offs_y + getVisibleLines()) setCursor(); else draw_status_state(); break; } return 0; }
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(); draw_message("Find cancelled."); setCursor(); 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 (GetAsyncKeyState(VK_SHIFT)&0x8000) { 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 407: case 'Z'-'A'+1: if (!(GetAsyncKeyState(VK_SHIFT)&0x8000)) { if (m_undoStack_pos > 0) { m_undoStack_pos--; loadUndoState(m_undoStack.Get(m_undoStack_pos)); draw(); char buf[512]; snprintf(buf,sizeof(buf),"Undid action -- %d items in undo buffer",m_undoStack_pos); draw_message(buf); setCursor(); } else draw_message("Can't Undo"); break; } // fall through case 'Y'-'A'+1: if (m_undoStack_pos < m_undoStack.GetSize()-1) { m_undoStack_pos++; loadUndoState(m_undoStack.Get(m_undoStack_pos)); draw(); char buf[512]; snprintf(buf,sizeof(buf),"Redid action -- %d items in redo buffer",m_undoStack.GetSize()-m_undoStack_pos-1); draw_message(buf); setCursor(); } else draw_message("Can't Redo"); break; case KEY_IC: if (!(GetAsyncKeyState(VK_SHIFT)&0x8000)) { s_overwrite=!s_overwrite; setCursor(); break; } // fqll through case 'V'-'A'+1: { // 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(); draw_message("Pasted"); saveUndoState(); setCursor(); } else { draw_message("Clipboard empty"); setCursor(); } } break; case KEY_DC: if (!(GetAsyncKeyState(VK_SHIFT)&0x8000)) { 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 (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(); draw_message(status); setCursor(); } break; case 'A'-'A'+1: 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 (m_selecting) { m_selecting=0; draw(); setCursor(); break; } return 0; case KEY_F3: case 'G'-'A'+1: if (s_search_string[0]) { runSearch(); return 0; } case 'F'-'A'+1: draw_message(""); attrset(m_color_message); bkgdset(m_color_message); mvaddstr(LINES-1,0,"Find string (ESC to cancel): "); addstr(s_search_string); clrtoeol(); attrset(0); bkgdset(0); m_state=-3; // find, initial (m_state=4 when we've typed something) return 0; case KEY_DOWN: { if (GetAsyncKeyState(VK_CONTROL)&0x8000) { if (m_offs_y < m_text.GetSize() - 4) { m_offs_y++; if (m_curs_y < m_offs_y) m_curs_y = m_offs_y; 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 (GetAsyncKeyState(VK_CONTROL)&0x8000) { if (m_offs_y>0) { m_offs_y--; if (m_curs_y>m_offs_y + getVisibleLines() - 1) m_curs_y = m_offs_y + getVisibleLines() - 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_offs_y) { m_curs_y=m_offs_y; if (m_curs_y < 0) m_curs_y=0; } else { m_curs_y -= getVisibleLines(); if (m_curs_y < 0) m_curs_y=0; m_offs_y=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: { if (m_curs_y >= m_offs_y+getVisibleLines() - 1) m_offs_y=m_curs_y+1; m_curs_y = m_offs_y+getVisibleLines() - 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 (GetAsyncKeyState(VK_CONTROL)&0x8000) { 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 (GetAsyncKeyState(VK_CONTROL)&0x8000) { 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 (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 (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: 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; }