LONG MnTextView::OnMsg_EM_SETSEL(long nStart, long nEnd) { if (nStart == -1) { nStart = m_nSelectionEnd; nEnd = nStart; } CHAR_POS cp_start; CHAR_POS cp_end; if (FilePosToCharPos(nStart, &cp_start) && FilePosToCharPos(nEnd, &cp_end)) { m_visualLineView.setSelection(cp_start, cp_end); } InvalidateRange(m_nSelectionStart, m_nSelectionEnd); m_nSelectionStart = nStart; m_nSelectionEnd = nEnd; //m_nCursorOffset = nEnd; FilePosToCharPos(m_nSelectionEnd, &m_CurrentCharPos); updateCaretPos(m_CurrentCharPos); InvalidateRange(m_nSelectionStart, m_nSelectionEnd); return 0; }
LONG TextViewBase::OnLButtonDblClick(UINT nFlags, int mx, int my) { // remove any existing selection InvalidateRange(m_nSelectionStart, m_nSelectionEnd); ULONG lineno, fileoff; int xpos; // map the mouse-coordinates to a real file-offset-coordinate MouseCoordToFilePos(mx, my, &lineno, &fileoff, &xpos); //m_nAnchorPosX = m_nCaretPosX; // move selection-start to start of word MoveWordStart(); m_nSelectionStart = m_nSelectionEnd;// m_nCursorOffset; // move selection-end to end of word MoveWordEnd(); //m_nSelectionEnd = m_nCursorOffset; // update caret position InvalidateRange(m_nSelectionStart, m_nSelectionEnd); //UpdateCaretOffset(m_nCursorOffset, TRUE, &m_nCaretPosX, &m_nCurrentLine); //m_nAnchorPosX = m_nCaretPosX; RepositionCaret(); NotifyParent(TVN_CURSOR_CHANGE); NotifyParent(TVN_SELECTION_CHANGED); return 0; }
void DataView::UpdateFromEditor(BMessage *message) { if (fData == NULL) return; BAutolock locker(fEditor); fFileSize = fEditor.FileSize(); // get the range of the changes int32 start = 0, end = fDataSize - 1; off_t offset, size; if (message != NULL && message->FindInt64("offset", &offset) == B_OK && message->FindInt64("size", &size) == B_OK) { if (offset > fOffset + (off_t)fDataSize || offset + (off_t)size < fOffset) { // the changes are not within our scope, so we can ignore them return; } if (offset > fOffset) start = offset - fOffset; if (offset + (off_t)size < fOffset + (off_t)fDataSize) end = offset + size - fOffset; } if (fOffset + (off_t)fDataSize > fFileSize) fSizeInView = fFileSize - fOffset; else fSizeInView = fDataSize; const uint8 *data; if (fEditor.GetViewBuffer(&data) == B_OK) // ToDo: copy only the relevant part memcpy(fData, data, fDataSize); InvalidateRange(start, end); // we notify our selection listeners also if the // data in the selection has changed if (start <= fEnd && end >= fStart) { BMessage update; update.AddInt64("start", fStart); update.AddInt64("end", fEnd); SendNotices(kDataViewSelection, &update); } }
// Sets the selected region. Note that this does not mean that any of this // region will actually become visible to the user unless it is within the // current display (see SetScroll). To let the user see (at least some of) // the region use DisplayCaret(). If p1 == p2 then this is the same as // calling SetCaret(). The boolean parameter base1 (default false) determines // how basepos_ (base address for selections) is set -- if base1 is false // then basepos_ is the smaller of p1 and p2, if true the basepos_ becomes p1. void CScrView::SetSel(CPointAp p1, CPointAp p2, bool base1) { // Save current selection CPointAp start = caretpos_; CPointAp end = selpos_; // Check/get valid caret locations and move selection there ValidateCaret(p2); ValidateCaret(p1); caret_hide(); if (p1.y < p2.y || (p1.y == p2.y && p1.x < p2.x)) { basepos_ = caretpos_ = p1; selpos_ = p2; } else { basepos_ = caretpos_ = p2; selpos_ = p1; } if (base1) basepos_ = p1; // Cause prev. selection to be redrawn (unselected) and new selection drawn (selected) if (start != caretpos_ || end != selpos_) { // We invalidate everything - TODO this should be optimised to only do the changed bit InvalidateRange(start, end); InvalidateRange(caretpos_, selpos_); // Alternative (whole selection range) invalidation InvalidateRange(start, end, true); InvalidateRange(caretpos_, selpos_, true); } caret_show(); }
NS_IMETHODIMP nsTreeSelection::ClearRange(PRInt32 aStartIndex, PRInt32 aEndIndex) { nsresult rv = SetCurrentIndex(aEndIndex); if (NS_FAILED(rv)) return rv; if (mFirstRange) { PRInt32 start = aStartIndex < aEndIndex ? aStartIndex : aEndIndex; PRInt32 end = aStartIndex < aEndIndex ? aEndIndex : aStartIndex; mFirstRange->RemoveRange(start, end); if (mTree) mTree->InvalidateRange(start, end); } return NS_OK; }
void CScrView::OnSelUpdate(CPoint point) { // Keep the last drag position so we only invalidate what has changed. CPointAp last; ASSERT(basepos_ == caretpos_ || basepos_ == selpos_); if (caretpos_ == basepos_) last = selpos_; else last = caretpos_; CRect cli; // Display area (client coords) GetDisplayRect(&cli); CRectAp disp = ConvertFromDP(cli); // Display area ("cli") in our coords CPointAp pp = ConvertFromDP(point); // Mouse point ("point") in our coords // Get display rect shrunk to only contain whole rows/columns CRectAp rr(disp); rr.top = ((rr.top - 1)/line_.cy + 1)*line_.cy; rr.left = ((rr.left- 1)/line_.cx + 1)*line_.cx; rr.bottom = (rr.bottom/line_.cy)*line_.cy; rr.right = (rr.right /line_.cx)*line_.cx; // Test if we are about to scroll or very close to edge if (!rr.PtInRect(pp)) { // TODO: We probably should handle vertical and horizontal auto-scrolling // separately and not allow both at the same time, to avoid confusion. CPointAp newpos(-1, -1); // New scroll position (our coords) static clock_t last_clock = 0; if (pp.x < rr.left) { newpos.x = scrollpos_.x - line_.cx; } else if (pp.x >= rr.right) { newpos.x = scrollpos_.x + line_.cx; } if (pp.y < rr.top) { // Use clock to ensure scrolling does not get faster with more mouse move events clock_t curr_clock = clock(); clock_t diff_clock = curr_clock - last_clock; if (diff_clock > CLOCKS_PER_SEC/5) diff_clock = CLOCKS_PER_SEC/5; // Scroll speed depends on distance mouse is above window // int diff_pixel = ((disp.top - pp.y)*(disp.top - pp.y))/10; int diff_pixel = int(disp.top - pp.y); int autoscroll = (int)pow((double)diff_pixel, autoscroll_accel_/10.0); __int64 to_move = 0; // How much to scroll up // Always scroll so that top of text line is at top of window if (disp.top < rr.top) to_move = line_.cy - (rr.top - disp.top); // If enough time has passed or mouse is far enough above the window... if (disp.top > pp.y && diff_clock * autoscroll >= CLOCKS_PER_SEC/5) { // Scroll according to time and distance to_move += line_.cy*((diff_clock * autoscroll)/(CLOCKS_PER_SEC/5)); last_clock = curr_clock; } newpos.y = scrollpos_.y - to_move; if (newpos.y < 0) newpos.y = 0; } else if (pp.y >= rr.bottom) { // See above comments (same but for bottom of window not top) clock_t curr_clock = clock(); clock_t diff_clock = curr_clock - last_clock; if (diff_clock > CLOCKS_PER_SEC/5) diff_clock = CLOCKS_PER_SEC/5; int diff_pixel = int(pp.y - disp.bottom); int autoscroll = (int)pow((double)diff_pixel, autoscroll_accel_/10.0); __int64 to_move = 0; if (disp.bottom > rr.bottom) to_move = line_.cy - (disp.bottom - rr.bottom); if (disp.bottom < pp.y && diff_clock * autoscroll >= CLOCKS_PER_SEC/5) { to_move += line_.cy*((diff_clock * autoscroll)/(CLOCKS_PER_SEC/5)); last_clock = curr_clock; } newpos.y = scrollpos_.y + to_move; if (newpos.y < 0) newpos.y = 0; } SetScroll(newpos, TRUE); } // Set end of selection based on this point CPoint ptmp = point; // Get pp based on new value of "point" // Don't allow selection to extend outside window if (ptmp.y < cli.top) ptmp.y = cli.top; else if (ptmp.y >= cli.bottom) ptmp.y = cli.bottom - 1; if (ptmp.x < cli.left) ptmp.x = cli.left; else if (ptmp.x >= cli.right) ptmp.x = cli.right - 1; // Work out new selection pp = ConvertFromDP(ptmp); ValidateCaret(pp, FALSE); if (pp.y < basepos_.y || (pp.y == basepos_.y && pp.x < basepos_.x)) { caretpos_ = pp; selpos_ = basepos_; } else { caretpos_ = basepos_; selpos_ = pp; } // Allow derived class to invalidate the whole selection if (pp.y != last.y || pp.x != last.x) InvalidateRange(caretpos_, selpos_, true); // Invalidate everything that's changed if (pp.y < last.y || (pp.y == last.y && pp.x < last.x)) InvalidateRange(pp, last); else if (pp.y != last.y || pp.x != last.x) InvalidateRange(last, pp); }
// // Process keyboard-navigation keys // LONG TextViewBase::OnKeyDown(UINT nKeyCode, UINT nFlags) { bool fCtrlDown = IsKeyPressed(VK_CONTROL); bool fShiftDown = IsKeyPressed(VK_SHIFT); BOOL fAdvancing = FALSE; long oldCursorOffset = m_nSelectionEnd; // // Process the key-press. Cursor movement is different depending // on if <ctrl> is held down or not, so act accordingly // switch(nKeyCode) { case VK_SHIFT: case VK_CONTROL: return 0; case 'a': case 'A': { if(fCtrlDown) SelectAll(); } return 0; // CTRL+Z undo case 'z': case 'Z': if(fCtrlDown && Undo()) /*NotifyParent(TVN_CHANGED);*/ return 0; // CTRL+Y redo case 'y': case 'Y': if(fCtrlDown && Redo()) //NotifyParent(TVN_CHANGED); return 0; // CTRL+C copy case 'c': case 'C': { //if(fCtrlDown && Redo()) // NotifyParent(TVN_CHANGED); if(fCtrlDown) return OnCopy(); else break; } case 'x': case 'X': { if(fCtrlDown) return OnCut(); else break; } case 'v': case 'V': { if(fCtrlDown) return OnPaste(); else break; } // Change insert mode / clipboard copy&paste case VK_INSERT: if(fCtrlDown) { OnCopy(); NotifyParent(TVN_CHANGED); } else if(fShiftDown) { OnPaste(); NotifyParent(TVN_CHANGED); } else { if(m_nEditMode == MODE_INSERT) m_nEditMode = MODE_OVERWRITE; else if(m_nEditMode == MODE_OVERWRITE) m_nEditMode = MODE_INSERT; NotifyParent(TVN_EDITMODE_CHANGE); } return 0; case VK_DELETE: if(m_nEditMode != MODE_READONLY) { if(fShiftDown) OnCut(); else ForwardDelete(); NotifyParent(TVN_CHANGED); } return 0; case VK_BACK: if(m_nEditMode != MODE_READONLY) { BackDelete(); fAdvancing = FALSE; NotifyParent(TVN_CHANGED); } return 0; case VK_LEFT: if(fCtrlDown) MoveWordPrev(); else MoveCharPrev(); fAdvancing = FALSE; break; case VK_RIGHT: if(fCtrlDown) MoveWordNext(); else MoveCharNext(); fAdvancing = TRUE; break; case VK_UP: if(fCtrlDown) Scroll(0, -1); else MoveLineUp(1); break; case VK_DOWN: if(fCtrlDown) Scroll(0, 1); else MoveLineDown(1); break; case VK_PRIOR: if(!fCtrlDown) MovePageUp(); break; case VK_NEXT: if(!fCtrlDown) MovePageDown(); break; case VK_HOME: if(fCtrlDown) MoveFileStart(); else MoveLineStart(m_nCurrentLine); break; case VK_END: if(fCtrlDown) MoveFileEnd(); else MoveLineEnd(m_nCurrentLine); break; default: return 0; } // Extend selection if <shift> is down if(fShiftDown) { InvalidateRange(m_nSelectionEnd, oldCursorOffset); //m_nSelectionEnd = m_nCursorOffset; } // Otherwise clear the selection else { if(m_nSelectionStart != m_nSelectionEnd) InvalidateRange(m_nSelectionStart, m_nSelectionEnd); //m_nSelectionEnd = m_nCursorOffset; m_nSelectionStart = m_nSelectionEnd; } // update caret-location (xpos, line#) from the offset //UpdateCaretOffset(m_nCursorOffset, fAdvancing, &m_nCaretPosX, &m_nCurrentLine); CHAR_POS cp; FilePosToCharPos(m_nSelectionEnd, &cp); m_nCurrentLine_D = cp.logLine; // maintain the caret 'anchor' position *except* for up/down actions if(nKeyCode != VK_UP && nKeyCode != VK_DOWN) { //m_nAnchorPosX = m_nCaretPosX; // scroll as necessary to keep caret within viewport //ScrollToPosition(m_nCaretPosX, m_nCurrentLine); } else { // scroll as necessary to keep caret within viewport if(!fCtrlDown); //ScrollToPosition(m_nCaretPosX, m_nCurrentLine); } NotifyParent(TVN_CURSOR_CHANGE); return 0; }
// // TextView::EnterText // // Import the specified text into the TextView at the current // cursor position, replacing any text-selection in the process // ULONG TextViewBase::EnterText(const TCHAR *szText, ULONG nLength) { #ifdef _DEBUG wchar_t db_string[200]; wsprintf(db_string, L"EnterText m_nSelectionEnd=%d\n", m_nSelectionEnd); OutputDebugString(db_string); #endif ULONG selstart = min(m_nSelectionStart, m_nSelectionEnd); ULONG selend = max(m_nSelectionStart, m_nSelectionEnd); BOOL fReplaceSelection = (selstart == selend) ? FALSE : TRUE; ULONG erase_len = nLength; ULONG line_offset = 0, line_length = 0; bool result = m_pTextDoc->lineinfo_from_lineno(m_nCurrentLine_D, &line_offset, &line_length, NULL, NULL); if(m_nCurrentLine_D != 0 && !result) { int stop = 1; throw MnException(); } switch(m_nEditMode) { case MODE_READONLY: return 0; case MODE_INSERT: // if there is a selection then remove it if(fReplaceSelection) { // group this erase with the insert/replace operation m_pTextDoc->m_seq.group(); m_pTextDoc->erase_text(selstart, selend-selstart); m_nSelectionEnd = selstart; } if(!m_pTextDoc->insert_text(m_nSelectionEnd, szText, nLength)) return 0; if(fReplaceSelection) m_pTextDoc->m_seq.ungroup(); break; case MODE_OVERWRITE: if(fReplaceSelection) { erase_len = selend - selstart; m_nSelectionEnd = selstart; } else { //ULONG lastPosition; ULONG lineoff; ULONG length_CRLF; /* USPCACHE *uspCache = GetUspCache(0, m_nCurrentLine, &lineoff);*/ GetOffsetAndLength_CRLF( m_nCurrentLine_D, &lineoff, &length_CRLF); // single-character overwrite - must behave like 'forward delete' // and remove a whole character-cluster (i.e. maybe more than 1 char) if(nLength == 1) { ULONG oldpos = m_nSelectionEnd; MoveCharNext(); erase_len = m_nSelectionEnd - oldpos; m_nSelectionEnd = oldpos; } // if we are at the end of a line (just before the CRLF) then we must // not erase any text - instead we act like a regular insertion if (m_nSelectionEnd == lineoff + length_CRLF) erase_len = 0; } if(!m_pTextDoc->replace_text(m_nSelectionEnd, szText, nLength, erase_len)) return 0; break; default: return 0; } // update cursor+selection positions m_nSelectionEnd += nLength; m_nSelectionStart = m_nSelectionEnd; //m_nSelectionEnd = m_nCursorOffset; // we altered the document, recalculate line+scrollbar information //RefreshWindow(); int a1 = '\n'; int a2 = '\r'; //ULONG offset, len; if(nLength == 1 && !fReplaceSelection && line_length < MAX_LINE_LENGTH - 1) { FilePosToCharPos(m_nSelectionEnd, &m_CurrentCharPos); if(szText[0] =='\n' ) { wchar_t debug[50]; wsprintf(debug, L"newline m_nCursorOffset%d", m_nSelectionEnd); OutputDebugString(debug); Smeg(TRUE); } else if(szText[0] =='\r') { } else { m_pTextDoc->init_linebuffer(); ResetLineCache( m_nCurrentLine_D); InvalidateRange(m_nSelectionEnd - 1, line_offset + line_length + 1); RepositionCaret(); } }else { //ResetLineCache( ); Smeg(TRUE); } NotifyParent(TVN_CURSOR_CHANGE); return nLength; }
BOOL TextViewBase::BackDelete() { ULONG selstart = min(m_nSelectionStart, m_nSelectionEnd); ULONG selend = max(m_nSelectionStart, m_nSelectionEnd); ULONG length = selend - selstart; bool nead_Smeg = false; ULONG line_offset, line_length, line_no; m_pTextDoc->lineinfo_from_offset(selstart, &line_no, &line_offset, &line_length, NULL, NULL); //m_pTextDoc->lineinfo_from_lineno(m_nCurrentLine_D, &line_offset, &line_length, NULL, NULL); // if there's a selection then delete it if(selstart != selend) { if(selstart + length >= line_length + line_offset) { nead_Smeg = true; } m_pTextDoc->erase_text(selstart, selend-selstart); m_nSelectionEnd = selstart; m_pTextDoc->m_seq.breakopt(); } // otherwise do a back-delete else if (m_nSelectionEnd > 0) { //m_nCursorOffset--; ULONG oldpos = m_nSelectionEnd; MoveCharPrev(); length = oldpos - m_nSelectionEnd; if (m_nSelectionEnd < line_offset) { nead_Smeg = true; } m_pTextDoc->erase_text(m_nSelectionEnd, length); } m_nSelectionStart = m_nSelectionEnd; //m_nSelectionEnd = m_nCursorOffset; //FilePosToCharPos(m_nCursorOffset, &m_CurrentCharPos); if(nead_Smeg) { Smeg(FALSE); }else { int old_offset = m_nSelectionEnd; m_pTextDoc->init_linebuffer(); ResetLineCache( m_nCurrentLine_D); //FilePosToCharPos(m_nCursorOffset, &m_CurrentCharPos); MoveLineStart(0, false); InvalidateRange((m_nSelectionEnd ? m_nSelectionEnd - 1 : 0), line_offset + line_length); m_nSelectionEnd = old_offset; RepositionCaret(); } #ifdef _DEBUG wchar_t db_string[200]; wsprintf(db_string, L"m_nSelectionEnd=%d\n", m_nSelectionEnd); OutputDebugString(db_string); #endif return TRUE; }
BOOL TextViewBase::ForwardDelete() { ULONG selstart = min(m_nSelectionStart, m_nSelectionEnd); ULONG selend = max(m_nSelectionStart, m_nSelectionEnd); ULONG length = selend - selstart; bool nead_Smeg = false; ULONG line_offset, line_length, line_no; m_pTextDoc->lineinfo_from_offset(selstart, &line_no, &line_offset, &line_length,NULL, NULL); if(selstart != selend) { if(selstart + length >= line_length + line_offset) { nead_Smeg = true; } m_pTextDoc->erase_text(selstart, length); //m_nCursorOffset = selstart; m_pTextDoc->m_seq.breakopt(); } else { ULONG oldpos = m_nSelectionEnd; MoveCharNext(); length = m_nSelectionEnd - oldpos; m_pTextDoc->erase_text(oldpos, length); m_nSelectionEnd = oldpos; if(oldpos + length >= line_length + line_offset) { nead_Smeg = true; } //else // m_pTextDoc->erase_text(m_nCursorOffset, 1); } m_nSelectionStart = selstart; m_nSelectionEnd = selstart; FilePosToCharPos(selstart, &m_CurrentCharPos); if(nead_Smeg) { Smeg(FALSE); }else { m_pTextDoc->init_linebuffer(); if(m_pTextDoc->lineinfo_from_lineno(m_nCurrentLine_D, &line_offset, &line_length ,NULL,NULL)) { ResetLineCache( m_nCurrentLine_D); InvalidateRange(min(m_nSelectionEnd - 1, 0), line_offset + line_length); RepositionCaret(); } } return TRUE; }
LRESULT HexView::OnKeyDown(UINT nVirtualKey, UINT nRepeatCount, UINT nFlags) { BOOL fForceUpdate = FALSE; bool fCtrlDown = IsKeyDown(VK_CONTROL); bool fShiftDown = IsKeyDown(VK_SHIFT); size_w oldoffset = m_nCursorOffset; fForceUpdate = !IsKeyDown(VK_SHIFT); if(nVirtualKey == VK_CONTROL || nVirtualKey == VK_SHIFT || nVirtualKey == VK_MENU) return 0; switch(nVirtualKey) { case VK_ESCAPE: fForceUpdate = TRUE; break; case VK_INSERT: if(fCtrlDown) { OnCopy(); } else if(fShiftDown) { OnPaste(); } else { if(m_nEditMode == HVMODE_INSERT) m_nEditMode = HVMODE_OVERWRITE; else if(m_nEditMode == HVMODE_OVERWRITE) m_nEditMode = HVMODE_INSERT; NotifyParent(HVN_EDITMODE_CHANGE); } return 0; case 'z': case 'Z': m_nSubItem = 0; if(fCtrlDown) Undo(); return 0; // CTRL+Y redo case 'y': case 'Y': m_nSubItem = 0; if(fCtrlDown) Redo(); return 0; case VK_DELETE: // can only erase when in Insert mode if(m_nEditMode == HVMODE_INSERT || CheckStyle(HVS_ALWAYSDELETE) && (m_nEditMode == HVMODE_INSERT || m_nEditMode == HVMODE_OVERWRITE) && SelectionSize() == 0) { ForwardDelete(); } else if(m_nEditMode != HVMODE_READONLY) { BYTE b[] = { 0 }; FillData(b, 1, SelectionSize()); } return 0; case VK_BACK: // can only erase when in Insert mode if(m_nEditMode == HVMODE_INSERT || CheckStyle(HVS_ALWAYSDELETE) && (m_nEditMode == HVMODE_INSERT || m_nEditMode == HVMODE_OVERWRITE)) { BackDelete(); } else { //PostMessage(m_hWnd, WM_KEYDOWN, INPUT inp = { INPUT_KEYBOARD }; inp.ki.wVk = VK_LEFT; SendInput(1, &inp, sizeof(inp)); } return 0; case VK_LEFT: //if ctrl held down, then scroll the viewport around! if(IsKeyDown(VK_CONTROL)) { PostMessage(m_hWnd, WM_HSCROLL, SB_LINEUP, 0L); return 0; } if(m_nCursorOffset > 0) m_nCursorOffset--; m_fCursorAdjustment = FALSE; break; case VK_RIGHT: //if ctrl held down, then scroll the viewport around! if(IsKeyDown(VK_CONTROL)) { PostMessage(m_hWnd, WM_HSCROLL, SB_LINEDOWN, 0L); return 0; } if(m_nCursorOffset < m_pDataSeq->size()) { m_nCursorOffset++; if(m_nCursorOffset == m_pDataSeq->size() && m_pDataSeq->size() % m_nBytesPerLine == 0) m_fCursorAdjustment = TRUE; else m_fCursorAdjustment = FALSE; } break; case VK_UP: //if ctrl held down, then scroll the viewport around! if(IsKeyDown(VK_CONTROL)) { PostMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L); return 0; } if(m_nCursorOffset > (unsigned)m_nBytesPerLine) m_nCursorOffset -= m_nBytesPerLine; break; case VK_DOWN: //if ctrl held down, then scroll the viewport around! if(IsKeyDown(VK_CONTROL)) { PostMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L); return 0; } m_nCursorOffset += min((size_w)m_nBytesPerLine, m_pDataSeq->size() - m_nCursorOffset); // if in the last partial line, don't go to end of file, rather // stay at "bottom" of file/window if(m_nCursorOffset >= m_pDataSeq->size() && !m_fCursorAdjustment) { // test if in a partial line if( oldoffset % m_nBytesPerLine < m_pDataSeq->size() % m_nBytesPerLine || m_pDataSeq->size() % m_nBytesPerLine == 0) { m_nCursorOffset = oldoffset; fForceUpdate = TRUE; } } break; case VK_HOME: //if ctrl held down, then scroll the viewport around! if(fCtrlDown) { m_nCursorOffset = 0; PostMessage(m_hWnd, WM_VSCROLL, SB_TOP, 0L); } else { if(m_fCursorAdjustment && m_nCursorOffset > 0) m_nCursorOffset--; m_nCursorOffset -= m_nCursorOffset % m_nBytesPerLine; } m_fCursorAdjustment = FALSE; break; case VK_END: if(IsKeyDown(VK_CONTROL)) { m_nCursorOffset = m_pDataSeq->size(); if(m_nCursorOffset % m_nBytesPerLine == 0) m_fCursorAdjustment = TRUE; PostMessage(m_hWnd, WM_VSCROLL, SB_BOTTOM, 0L); } else { // if not already at very end of line if(m_fCursorAdjustment == FALSE) { if(m_pDataSeq->size() - m_nBytesPerLine >= m_nCursorOffset && m_pDataSeq->size() >= m_nBytesPerLine) { m_nCursorOffset += m_nBytesPerLine - (m_nCursorOffset % m_nBytesPerLine); m_fCursorAdjustment = TRUE; } else { m_nCursorOffset += m_pDataSeq->size()-m_nCursorOffset; } } if(m_nCursorOffset >= m_pDataSeq->size() && m_pDataSeq->size() % m_nBytesPerLine == 0) m_fCursorAdjustment = TRUE; } break; case VK_PRIOR: // pageup m_nCursorOffset -= min(m_nCursorOffset, (size_w)m_nBytesPerLine * m_nWindowLines); break; case VK_NEXT: // pagedown m_nCursorOffset += min(m_pDataSeq->size() - m_nCursorOffset, (size_w)m_nBytesPerLine * m_nWindowLines); if(m_nCursorOffset >= m_pDataSeq->size() && m_pDataSeq->size() % m_nBytesPerLine == 0) { m_fCursorAdjustment = TRUE; } break; case VK_TAB: m_nWhichPane ^= 1; fForceUpdate = TRUE; if(m_ColourList[HVC_SELECTION] != m_ColourList[HVC_SELECTION2]) { InvalidateRange(m_nSelectionStart, m_nSelectionEnd); } break; default: // don't know what this key is, so exit return 0; } m_nSubItem = 0; if(m_nCursorOffset != oldoffset || fForceUpdate) { // SHIFT key being held down? if(IsKeyDown(VK_SHIFT)) { // extend the selection m_nSelectionEnd = m_nCursorOffset; InvalidateRange(oldoffset, m_nSelectionEnd); } else if(nVirtualKey != VK_TAB) { // clear any selection if(m_nSelectionEnd != m_nSelectionStart) InvalidateRange(m_nSelectionEnd, m_nSelectionStart); m_nSelectionEnd = m_nCursorOffset; m_nSelectionStart = m_nCursorOffset; } ScrollToCaret(); NotifyParent(HVN_CURSOR_CHANGE); if(nVirtualKey == VK_NEXT || nVirtualKey == VK_PRIOR) { RefreshWindow(); } } return 0; }