OSDN Git Service

Change icon.ico. And fix icon bug, write ChangeLog.txt.
[ckw/ckw.git] / selection.cpp
1 /*-----------------------------------------------------------------------------
2  * File: selection.cpp
3  *-----------------------------------------------------------------------------
4  * Copyright (c) 2004-2005  Kazuo Ishii <k-ishii@wb4.so-net.ne.jp>
5  *                              - original version
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *---------------------------------------------------------------------------*/
21 #include "ckw.h"
22
23 static int      gSelectMode = 0;
24 static COORD    gSelectPos = { -1, -1 }; // pick point
25 static SMALL_RECT gSelectRect = { -1, -1, -1, -1 }; // expanded selection area
26
27 static const wchar_t WORD_BREAK_CHARS[] = {
28         L' ',  L'\t', L'\"', L'&', L'\'', L'(', L')', L'*',
29         L',',  L';',  L'<',  L'=', L'>',  L'?', L'@', L'[',
30         L'\\', L']',  L'^',  L'`', L'{',  L'}', L'~',
31         0x3000,
32         0x3001,
33         0x3002,
34         /**/
35         0,
36 };
37
38 /*****************************************************************************/
39
40 #define SCRN_InvalidArea(x,y) \
41         (y < gCSI->srWindow.Top    ||   \
42          y > gCSI->srWindow.Bottom ||   \
43          x < gCSI->srWindow.Left   ||   \
44          x > gCSI->srWindow.Right)
45
46 #define SELECT_GetScrn(x,y) \
47         (gScreen + CSI_WndCols(gCSI) * (y - gCSI->srWindow.Top) + x)
48
49 static void __select_word_expand_left()
50 {
51         if(SCRN_InvalidArea(gSelectRect.Left, gSelectRect.Top))
52                 return;
53         CHAR_INFO* base  = SELECT_GetScrn(gSelectRect.Left, gSelectRect.Top);
54         CHAR_INFO* ptr = base;
55         int c = gSelectRect.Left;
56
57         for( ; c >= gCSI->srWindow.Left ; c--, ptr--) {
58                 if(wcschr(WORD_BREAK_CHARS, ptr->Char.UnicodeChar)) {
59                         c++;
60                         break;
61                 }
62         }
63         if(c < 0)
64                 c = 0;
65
66         if(gSelectRect.Left > c)
67                 gSelectRect.Left = c;
68 }
69
70 static void __select_word_expand_right()
71 {
72         if(SCRN_InvalidArea(gSelectRect.Right, gSelectRect.Bottom))
73                 return;
74         CHAR_INFO* base  = SELECT_GetScrn(gSelectRect.Right, gSelectRect.Bottom);
75         CHAR_INFO* ptr = base;
76         int c = gSelectRect.Right;
77
78         for( ; c <= gCSI->srWindow.Right ; c++, ptr++) {
79                 if(wcschr(WORD_BREAK_CHARS, ptr->Char.UnicodeChar)) {
80                         break;
81                 }
82         }
83
84         if(gSelectRect.Right < c)
85                 gSelectRect.Right = c;
86 }
87
88 static void __select_char_expand()
89 {
90         CHAR_INFO* base;
91
92         if(SCRN_InvalidArea(gSelectRect.Left, gSelectRect.Top)) {
93         }
94         else if(gSelectRect.Left-1 >= gCSI->srWindow.Left) {
95                 base  = SELECT_GetScrn(gSelectRect.Left, gSelectRect.Top);
96                 if(base->Attributes & COMMON_LVB_TRAILING_BYTE)
97                         gSelectRect.Left--;
98         }
99
100         if(SCRN_InvalidArea(gSelectRect.Right, gSelectRect.Bottom)) {
101         }
102         else {
103                 base  = SELECT_GetScrn(gSelectRect.Right, gSelectRect.Bottom);
104                 if(base->Attributes & COMMON_LVB_TRAILING_BYTE)
105                         gSelectRect.Right++;
106         }
107 }
108
109 inline void __select_expand()
110 {
111         if(gSelectMode == 0) {
112                 __select_char_expand();
113         }
114         else if(gSelectMode == 1) {
115                 __select_word_expand_left();
116                 __select_word_expand_right();
117         }
118         else if(gSelectMode == 2) {
119                 gSelectRect.Left = gCSI->srWindow.Left;
120                 gSelectRect.Right = gCSI->srWindow.Right+1;
121         }
122 }
123
124 static void window_to_charpos(int& x, int& y)
125 {
126         x -= gBorderSize;
127         y -= gBorderSize;
128         if(x < 0) x = 0;
129         if(y < 0) y = 0;
130         x /= gFontW;
131         y /= gFontH;
132         x += gCSI->srWindow.Left;
133         y += gCSI->srWindow.Top;
134         if(x > gCSI->srWindow.Right)  x = gCSI->srWindow.Right+1;
135         if(y > gCSI->srWindow.Bottom) y = gCSI->srWindow.Bottom;
136 }
137
138 /*****************************************************************************/
139
140 static inline bool __select_invalid()
141 {
142         return ( gSelectRect.Top > gSelectRect.Bottom ||
143                  (gSelectRect.Top == gSelectRect.Bottom &&
144                  gSelectRect.Left >= gSelectRect.Right) );
145 }
146
147 /*----------*/
148 BOOL    selectionGetArea(SMALL_RECT& sr)
149 {
150         if( __select_invalid() )
151                 return(FALSE);
152         sr = gSelectRect;
153         return(TRUE);
154 }
155
156 /*----------*/
157 void    selectionClear(HWND hWnd)
158 {
159         if( __select_invalid() )
160                 return;
161         gSelectRect.Left = gSelectRect.Right = \
162         gSelectRect.Top = gSelectRect.Bottom = 0;
163         InvalidateRect(hWnd, NULL, FALSE);
164 }
165
166 /*----------*/
167 wchar_t * selectionGetString()
168 {
169         if( __select_invalid() )
170                 return(NULL);
171
172         int nb, y;
173
174         if(gSelectRect.Top == gSelectRect.Bottom) {
175                 nb = gSelectRect.Right - gSelectRect.Left;
176         }
177         else {
178                 nb = gCSI->srWindow.Right - gSelectRect.Left+1;
179                 for(y = gSelectRect.Top+1 ; y <= gSelectRect.Bottom-1 ; y++)
180                         nb += CSI_WndCols(gCSI);
181                 nb += gSelectRect.Right - gCSI->srWindow.Left;
182         }
183
184         COORD      size = { CSI_WndCols(gCSI), 1 };
185         CHAR_INFO* work = new CHAR_INFO[ size.X ];
186         wchar_t*   buffer = new wchar_t[ nb +32 ];
187         wchar_t*   wp = buffer;
188         COORD      pos = { 0,0 };
189         SMALL_RECT sr = { gCSI->srWindow.Left, 0, gCSI->srWindow.Right, 0 };
190
191         *wp = 0;
192
193         if(gSelectRect.Top == gSelectRect.Bottom) {
194                 sr.Top = sr.Bottom = gSelectRect.Top;
195                 ReadConsoleOutput_Unicode(gStdOut, work, size, pos, &sr);
196                 copyChar(wp, work, gSelectRect.Left, gSelectRect.Right-1, false);
197         }
198         else {
199                 sr.Top = sr.Bottom = gSelectRect.Top;
200                 ReadConsoleOutput_Unicode(gStdOut, work, size, pos, &sr);
201                 copyChar(wp, work, gSelectRect.Left, gCSI->srWindow.Right);
202                 for(y = gSelectRect.Top+1 ; y <= gSelectRect.Bottom-1 ; y++) {
203                         sr.Top = sr.Bottom = y;
204                         ReadConsoleOutput_Unicode(gStdOut, work, size, pos, &sr);
205                         copyChar(wp, work, gCSI->srWindow.Left, gCSI->srWindow.Right);
206                 }
207                 sr.Top = sr.Bottom = gSelectRect.Bottom;
208                 ReadConsoleOutput_Unicode(gStdOut, work, size, pos, &sr);
209                 copyChar(wp, work, gCSI->srWindow.Left, gSelectRect.Right-1, false);
210         }
211
212         delete [] work;
213         return(buffer);
214 }
215
216 /*----------*/
217 void    onLBtnDown(HWND hWnd, int x, int y)
218 {
219         static DWORD    prev_time = 0;
220         static int      prevX = -100;
221         static int      prevY = -100;
222
223         {
224                 /* calc click count */
225                 DWORD now_time = GetTickCount();
226                 DWORD stime;
227                 if(prev_time > now_time)
228                         stime = now_time + ~prev_time+1;
229                 else
230                         stime = now_time - prev_time;
231                 if(stime <= GetDoubleClickTime()) {
232                         int sx = (prevX > x) ? prevX-x : x-prevX;
233                         int sy = (prevY > y) ? prevY-y : y-prevY;
234                         if(sx <= GetSystemMetrics(SM_CXDOUBLECLK) &&
235                            sy <= GetSystemMetrics(SM_CYDOUBLECLK)) {
236                                 if(++gSelectMode > 2)
237                                         gSelectMode = 0;
238                         }
239                         else {
240                                 gSelectMode = 0;
241                         }
242                 }
243                 else {
244                         gSelectMode = 0;
245                 }
246                 prev_time = now_time;
247                 prevX = x;
248                 prevY = y;
249         }
250
251         if(!gScreen || !gCSI)
252                 return;
253         window_to_charpos(x, y);
254         SetCapture(hWnd);
255
256         gSelectPos.X = x;
257         gSelectPos.Y = y;
258         gSelectRect.Left = gSelectRect.Right = x;
259         gSelectRect.Top  = gSelectRect.Bottom = y;
260
261         __select_expand();
262         InvalidateRect(hWnd, NULL, FALSE);
263 }
264
265 /*----------*/
266 void    onLBtnUp(HWND hWnd, int x, int y)
267 {
268         if(hWnd != GetCapture())
269                 return;
270         ReleaseCapture();
271         if(!gScreen || !gCSI)
272                 return;
273         //window_to_charpos(x, y);
274
275         wchar_t* str = selectionGetString();
276         if(!str) return;
277
278         copyStringToClipboard( hWnd, str );
279
280         delete [] str;
281 }
282
283 /*----------*/
284 void    onMouseMove(HWND hWnd, int x, int y)
285 {
286         if(hWnd != GetCapture())
287                 return;
288         if(!gScreen || !gCSI)
289                 return;
290         window_to_charpos(x, y);
291
292         SMALL_RECT bak = gSelectRect;
293
294         if(y < gSelectPos.Y || (y == gSelectPos.Y && x < gSelectPos.X)) {
295                 gSelectRect.Left   = x;
296                 gSelectRect.Top    = y;
297                 gSelectRect.Right  = gSelectPos.X;
298                 gSelectRect.Bottom = gSelectPos.Y;
299         }
300         else {
301                 gSelectRect.Left   = gSelectPos.X;
302                 gSelectRect.Top    = gSelectPos.Y;
303                 gSelectRect.Right  = x;
304                 gSelectRect.Bottom = y;
305         }
306         __select_expand();
307
308         if(memcmp(&bak, &gSelectRect, sizeof(bak))) {
309                 InvalidateRect(hWnd, NULL, FALSE);
310         }
311 }
312
313 /* EOF */