cursor.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 426 行
C
426 行
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
* DESCRIBE IT HERE!
*
****************************************************************************/
#include <string.h>
#include <assert.h>
#include "winvi.h"
#include "color.h"
#include "font.h"
#include "utils.h"
#include "win.h"
static int cursorHeight;
static int cursorWidth;
static cursor_type cursorType;
static UINT oldBlinkTime;
static bool haveOldBlinkTime;
static bool caretDisplayed = FALSE;
static bool caretKilled = FALSE;
extern int WinVirtualCursorPosition( char *, int );
/*
* SetCursorBlinkRate - set the rate of blinking for the caret
*/
void SetCursorBlinkRate( int cbr )
{
SetCaretBlinkTime( cbr );
CursorBlinkRate = cbr;
} /* SetCursorBlinkRate */
/*
* GoodbyeCursor - we are losing focus, so get rid of our cursor
*/
void GoodbyeCursor( HWND hwnd )
{
if( haveOldBlinkTime ) {
SetCaretBlinkTime( oldBlinkTime );
}
MyHideCaret( hwnd );
DestroyCaret();
} /* GoodbyeCursor */
/*
* NewCursor - create a new cursor for a window
*/
void NewCursor( window_id id, cursor_type ct )
{
window *w;
int height;
int width;
if( BAD_ID( id ) ) {
return;
}
w = WINDOW_FROM_ID( id );
height = FontHeight( WIN_FONT( w ) );
width = FontAverageWidth( WIN_FONT( w ) );
height = (long) height * ct.height / 100L;
width = (long) width * ct.width / 100L;
MyHideCaret( id );
DestroyCaret();
cursorHeight = height;
cursorWidth = width;
if( !haveOldBlinkTime ) {
oldBlinkTime = GetCaretBlinkTime();
haveOldBlinkTime = TRUE;
}
CreateCaret( id, (HBITMAP) NULL, cursorWidth, cursorHeight );
SetCursorBlinkRate( CursorBlinkRate );
MyShowCaret( id );
cursorType = ct;
} /* NewCursor */
static int getCursorInfo( HWND hwnd, int row, int col, int *x, int *width )
{
ss_block *ss, *ss_start, *ss_prev;
dc dc_line;
int len;
int old_col;
char *str;
int funny = 0;
col--; // we like base 0
row--;
// this section checks if current line is valid.
assert( hwnd == CurrentInfo->CurrentWindow );
if( row < 0 || row >= CurrentInfo->dc_size ) {
// not on screen -> not displayed
*x = -10;
*width = 0;
return( 0 );
}
dc_line = DCFindLine( row, hwnd );
if( dc_line->display != 0 ){
// line has not been drawn yet. Can't set cursor.
*x = -10;
*width = 0;
return( 0 );
}
assert( dc_line->valid );
if( dc_line->start_col != LeftColumn ) {
// not in cache -> not on screen -> not displayed
*x = -10;
*width = 0;
return( 0 );
}
ss_start = ss = dc_line->ss;
// this bit adjusts col for real tabs
if( EditFlags.RealTabs ){
// this takes it from the current line!!!! %$#@!
// what if row isn't the current line! oops!!!
// luckily this works because who wants to know cursor info
// for any line but the current one!
// if( thisLine == CurrentLine ){
int real_left = RealCursorPosition( LeftColumn+1 );
old_col = col;
col = RealCursorPosition( col+1 ) - real_left;
// kludge! - Real Cursor position refuses to say cursor is to right
// of last character like it ought to when Modeless
if( CursorPositionOffRight( old_col+1 ) &&
(EditFlags.Modeless==FALSE) ){
col++;
}
//} else {
// int real_left = RealCursorPositionOnLine(thisLine, LeftColumn+1 );
// old_col = col;
// col = RealCursorPositionOnLine(thisLine, col+1 ) - real_left;
//}
}
// this bit finds the block we want
while( ss->end < col ) {
ss++;
}
// handle cursor being off the right of text
if( ss->end == BEYOND_TEXT ) {
*width = FontAverageWidth( SEType[ ss->type ].font );
if( ss == ss_start ) {
*x = (*width) * col;
} else {
ss_prev = ss - 1;
*x = ( (*width) * ( col - ss_prev->end - 1 ) ) + ss_prev->offset;
}
return( 0 );
}
// setup to figure out where cursor is within text.
if( ss != ss_start ) {
ss_prev = ss - 1;
str = dc_line->text + ss_prev->end + 1;
len = col - ss_prev->end - 1;
} else {
str = dc_line->text;
len = col;
}
// Magic Tabs positioning
if( EditFlags.RealTabs ) {
type_style *this_style = &SEType[ss->type];
int no_tab = FALSE;
int avg_width = FontAverageWidth( SEType[ss->type].font );
int left, extent, end_tab;
char *cur_pos;
char *end_str;
if( ss != ss_start ) {
left = ss_prev->offset;
} else {
left = 0;
}
if( len > 0 ) {
// Note: this will not work with 16bit chars or embedded chars
// but niether will the drawing routines, so not to worry (yet)
// Is there a tab in the current block ?
end_str = cur_pos = str+len;
while( *(--cur_pos) != '\t' ){
if(cur_pos == str){
no_tab=TRUE;
break;
}
}
// if so, figure out where the last tab stop is.
if( no_tab == FALSE ){
// dist is the virtual curpos - the number of chars before
// the first tab. this should be the tab boundry.
int dist = (old_col+1) - (end_str-cur_pos);
// unless the end_str was also a tab, So we round down.
left = ( dist - (dist%HardTab) - LeftColumn ) *avg_width;
cur_pos++;
}
// now get the extent of the leading chars ...
extent = MyTextExtent( hwnd, this_style, cur_pos, end_str - cur_pos );
} else {
extent = 0;
cur_pos = str;
end_str = str;
}
// ... and find the position and width of the cursor.
if( *end_str == '\t' ){
// in strange case, tab may start before end of prev string
end_tab = (old_col - LeftColumn + 1 )*avg_width;
*x = min( left + extent, end_tab );
*width = max( end_tab - *x, 1 );
funny = 0;
} else {
*x = left + extent;
*width = MyTextExtent( hwnd, this_style, cur_pos,
end_str - cur_pos + 1 ) - extent;
funny = (*width)/2;
}
} else {
type_style *this_style = &SEType[ss->type];
*x = MyTextExtent( hwnd, this_style, str, len );
*width = MyTextExtent( hwnd, this_style, str, len + 1 ) - *x;
if( ss != ss_start ) {
*x += ss_prev->offset;
}
funny = (*width)/2;
}
if( FontIsFunnyItalic( SEType[ ss->type ].font ) ){
return( funny );
} else {
return( 0 );
}
}
int PixelFromColumnOnCurrentLine( int col )
{
int x, w;
getCursorInfo( CurrentWindow, CurrentLineNumber - TopOfPage + 1,
col - LeftColumn, &x, &w );
return( x );
}
/*
* SetCursorOnScreen - set cursor at specified row and column in edit window
*/
void SetCursorOnScreen( int row, int col )
{
window *w;
int x, y;
int width;
int funny;
if( BAD_ID( CurrentWindow ) ) {
return;
}
if( EditFlags.Quiet || EditFlags.NoSetCursor ) {
return;
}
funny = getCursorInfo( CurrentWindow, row, col, &x, &width );
w = WINDOW_FROM_ID( CurrentWindow );
y = row * FontHeight( WIN_FONT( w ) ) - cursorHeight;
width = (long) width * cursorType.width /100L;
if( cursorWidth != width ) {
MyHideCaret( CurrentWindow );
DestroyCaret();
CreateCaret( CurrentWindow, (HBITMAP) NULL, width, cursorHeight );
cursorWidth = width;
}
// adjust position for italic sillyness
SetCaretPos( x - funny , y );
MyShowCaret( CurrentWindow );
} /* SetCursorOnScreen */
/*
* SetCursorOnLine - set cursor at specified column in single line text string
*/
void SetCursorOnLine( window_id id, int col, char *str , type_style *style)
{
window *w;
int x, y;
int width, height;
if( BAD_ID( id ) ) {
return;
}
w = WINDOW_FROM_ID( id );
// y = FontHeight( WIN_FONT( w ) ) - cursorHeight;
x = MyTextExtent( id, style, str, col-1 );
width = MyTextExtent( id, style, str, col ) - x;
/* adjust so that Insert cursor is 0 width
* Also make the overstrike cursor the height of the insert cursor.
*/
width = (long) width * cursorType.width / 100L;
height = InsertCursorType.height;
y = FontHeight( WIN_FONT( w ) ) - height;
MyHideCaret( id );
DestroyCaret();
// CreateCaret( id, (HBITMAP) NULL, width, cursorHeight );
CreateCaret( id, (HBITMAP) NULL, width, height );
SetCaretPos( x, y );
MyShowCaret( id );
} /* SetCursorOnLine */
void SetGenericWindowCursor( window_id id, int row, int col )
{
// SetCursorOnScreen calls functions which are not generic
// ie) they only work on the current window! Therefore
// this routine does not do what the name implies!!!
id=id;
SetCursorOnScreen( row, col );
} /* SetGenericWindowCursor */
/*
* ResetEditWindowCursor - display cursor on setfocus to a buffer
*/
void ResetEditWindowCursor( window_id id )
{
if( !EditFlags.Modeless && !EditFlags.InsertModeActive ) {
NewCursor( id, NormalCursorType );
} else {
if( EditFlags.WasOverstrike ) {
NewCursor( id, OverstrikeCursorType );
} else {
NewCursor( id, InsertCursorType );
}
}
// position cursor in edit window
SetWindowCursor();
}
/*
* MyShowCaret - ShowCaret w/o additive effects
*/
void MyShowCaret( window_id id )
{
if( !caretDisplayed && !caretKilled ) {
ShowCaret( id );
caretDisplayed = TRUE;
}
}
/*
* MyHideCaret - HideCaret w/o additive effects
*/
void MyHideCaret( window_id id )
{
if( caretDisplayed ) {
HideCaret( id );
caretDisplayed = FALSE;
}
}
void MyKillCaret( window_id id )
{
if( !caretKilled ) {
MyHideCaret( id );
HideCaret( id );
caretKilled = TRUE;
}
}
void MyRaiseCaret( window_id id )
{
if( caretKilled ) {
ShowCaret( id );
caretKilled = FALSE;
MyShowCaret( id );
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?