Sync to trunk HEAD (r43416)
[reactos.git] / rosapps / dflat32 / listbox.c
1 /* ------------- listbox.c ------------ */
2
3 #include "dflat.h"
4
5 #ifdef INCLUDE_EXTENDEDSELECTIONS
6 static int ExtendSelections(DFWINDOW, int, int);
7 static void TestExtended(DFWINDOW, DF_PARAM);
8 static void ClearAllSelections(DFWINDOW);
9 static void SetSelection(DFWINDOW, int);
10 static void FlipSelection(DFWINDOW, int);
11 static void ClearSelection(DFWINDOW, int);
12 #else
13 #define TestExtended(w,p) /**/
14 #endif
15 static void ChangeSelection(DFWINDOW, int, int);
16 static void WriteSelection(DFWINDOW, int, int, DFRECT *);
17 static BOOL SelectionInWindow(DFWINDOW, int);
18
19 static int py = -1; /* the previous y mouse coordinate */
20
21 #ifdef INCLUDE_EXTENDEDSELECTIONS
22 /* --------- DF_SHIFT_F8 Key ------------ */
23 static void AddModeKey(DFWINDOW wnd)
24 {
25 if (DfIsMultiLine(wnd)) {
26 wnd->AddMode ^= TRUE;
27 DfSendMessage(DfGetParent(wnd), DFM_ADDSTATUS,
28 wnd->AddMode ? ((DF_PARAM) "Add Mode") : 0, 0);
29 }
30 }
31 #endif
32
33 /* --------- DF_UP (Up Arrow) Key ------------ */
34 static void UpKey(DFWINDOW wnd, DF_PARAM p2)
35 {
36 if (wnd->selection > 0) {
37 if (wnd->selection == wnd->wtop) {
38 DfBaseWndProc(DF_LISTBOX, wnd, DFM_KEYBOARD, DF_UP, p2);
39 DfPostMessage(wnd, DFM_LB_SELECTION, wnd->selection-1,
40 DfIsMultiLine(wnd) ? p2 : FALSE);
41 }
42 else {
43 int newsel = wnd->selection-1;
44 if (wnd->wlines == DfClientHeight(wnd))
45 while (*DfTextLine(wnd, newsel) == DF_LINE)
46 --newsel;
47 DfPostMessage(wnd, DFM_LB_SELECTION, newsel,
48 #ifdef INCLUDE_EXTENDEDSELECTIONS
49 DfIsMultiLine(wnd) ? p2 :
50 #endif
51 FALSE);
52 }
53 }
54 }
55
56 /* --------- DF_DN (Down Arrow) Key ------------ */
57 static void DnKey(DFWINDOW wnd, DF_PARAM p2)
58 {
59 if (wnd->selection < wnd->wlines-1) {
60 if (wnd->selection == wnd->wtop+DfClientHeight(wnd)-1) {
61 DfBaseWndProc(DF_LISTBOX, wnd, DFM_KEYBOARD, DF_DN, p2);
62 DfPostMessage(wnd, DFM_LB_SELECTION, wnd->selection+1,
63 DfIsMultiLine(wnd) ? p2 : FALSE);
64 }
65 else {
66 int newsel = wnd->selection+1;
67 if (wnd->wlines == DfClientHeight(wnd))
68 while (*DfTextLine(wnd, newsel) == DF_LINE)
69 newsel++;
70 DfPostMessage(wnd, DFM_LB_SELECTION, newsel,
71 #ifdef INCLUDE_EXTENDEDSELECTIONS
72 DfIsMultiLine(wnd) ? p2 :
73 #endif
74 FALSE);
75 }
76 }
77 }
78
79 /* --------- DF_HOME and DF_PGUP Keys ------------ */
80 static void HomePgUpKey(DFWINDOW wnd, DF_PARAM p1, DF_PARAM p2)
81 {
82 DfBaseWndProc(DF_LISTBOX, wnd, DFM_KEYBOARD, p1, p2);
83 DfPostMessage(wnd, DFM_LB_SELECTION, wnd->wtop,
84 #ifdef INCLUDE_EXTENDEDSELECTIONS
85 DfIsMultiLine(wnd) ? p2 :
86 #endif
87 FALSE);
88 }
89
90 /* --------- DF_END and DF_PGDN Keys ------------ */
91 static void EndPgDnKey(DFWINDOW wnd, DF_PARAM p1, DF_PARAM p2)
92 {
93 int bot;
94 DfBaseWndProc(DF_LISTBOX, wnd, DFM_KEYBOARD, p1, p2);
95 bot = wnd->wtop+DfClientHeight(wnd)-1;
96 if (bot > wnd->wlines-1)
97 bot = wnd->wlines-1;
98 DfPostMessage(wnd, DFM_LB_SELECTION, bot,
99 #ifdef INCLUDE_EXTENDEDSELECTIONS
100 DfIsMultiLine(wnd) ? p2 :
101 #endif
102 FALSE);
103 }
104
105 #ifdef INCLUDE_EXTENDEDSELECTIONS
106 /* --------- Space Bar Key ------------ */
107 static void SpacebarKey(DFWINDOW wnd, DF_PARAM p2)
108 {
109 if (DfIsMultiLine(wnd)) {
110 int sel = DfSendMessage(wnd, DFM_LB_CURRENTSELECTION, 0, 0);
111 if (sel != -1) {
112 if (wnd->AddMode)
113 FlipSelection(wnd, sel);
114 if (DfItemSelected(wnd, sel)) {
115 if (!((int) p2 & (DF_LEFTSHIFT | DF_RIGHTSHIFT)))
116 wnd->AnchorPoint = sel;
117 ExtendSelections(wnd, sel, (int) p2);
118 }
119 else
120 wnd->AnchorPoint = -1;
121 DfSendMessage(wnd, DFM_PAINT, 0, 0);
122 }
123 }
124 }
125 #endif
126
127 /* --------- Enter ('\r') Key ------------ */
128 static void EnterKey(DFWINDOW wnd)
129 {
130 if (wnd->selection != -1) {
131 DfSendMessage(wnd, DFM_LB_SELECTION, wnd->selection, TRUE);
132 DfSendMessage(wnd, DFM_LB_CHOOSE, wnd->selection, 0);
133 }
134 }
135
136 /* --------- All Other Key Presses ------------ */
137 static void KeyPress(DFWINDOW wnd, DF_PARAM p1, DF_PARAM p2)
138 {
139 int sel = wnd->selection+1;
140 while (sel < wnd->wlines) {
141 char *cp = DfTextLine(wnd, sel);
142 if (cp == NULL)
143 break;
144 #ifdef INCLUDE_EXTENDEDSELECTIONS
145 if (DfIsMultiLine(wnd))
146 cp++;
147 #endif
148 /* --- special for directory list box --- */
149 if (*cp == '[')
150 cp++;
151 if (tolower(*cp) == (int)p1) {
152 DfSendMessage(wnd, DFM_LB_SELECTION, sel,
153 DfIsMultiLine(wnd) ? p2 : FALSE);
154 if (!SelectionInWindow(wnd, sel)) {
155 wnd->wtop = sel-DfClientHeight(wnd)+1;
156 DfSendMessage(wnd, DFM_PAINT, 0, 0);
157 }
158 break;
159 }
160 sel++;
161 }
162 }
163
164 /* --------- DFM_KEYBOARD Message ------------ */
165 static int KeyboardMsg(DFWINDOW wnd, DF_PARAM p1, DF_PARAM p2)
166 {
167 switch ((int) p1) {
168 #ifdef INCLUDE_EXTENDEDSELECTIONS
169 case DF_SHIFT_F8:
170 AddModeKey(wnd);
171 return TRUE;
172 #endif
173 case DF_UP:
174 TestExtended(wnd, p2);
175 UpKey(wnd, p2);
176 return TRUE;
177 case DF_DN:
178 TestExtended(wnd, p2);
179 DnKey(wnd, p2);
180 return TRUE;
181 case DF_PGUP:
182 case DF_HOME:
183 TestExtended(wnd, p2);
184 HomePgUpKey(wnd, p1, p2);
185 return TRUE;
186 case DF_PGDN:
187 case DF_END:
188 TestExtended(wnd, p2);
189 EndPgDnKey(wnd, p1, p2);
190 return TRUE;
191 #ifdef INCLUDE_EXTENDEDSELECTIONS
192 case ' ':
193 SpacebarKey(wnd, p2);
194 break;
195 #endif
196 case '\r':
197 EnterKey(wnd);
198 return TRUE;
199 default:
200 KeyPress(wnd, p1, p2);
201 break;
202 }
203 return FALSE;
204 }
205
206 /* ------- DFM_LEFT_BUTTON Message -------- */
207 static int LeftButtonMsg(DFWINDOW wnd, DF_PARAM p1, DF_PARAM p2)
208 {
209 int my = (int) p2 - DfGetTop(wnd);
210 if (my >= wnd->wlines-wnd->wtop)
211 my = wnd->wlines - wnd->wtop;
212
213 if (!DfInsideRect(p1, p2, DfClientRect(wnd)))
214 return FALSE;
215 if (wnd->wlines && my != py) {
216 int sel = wnd->wtop+my-1;
217 #ifdef INCLUDE_EXTENDEDSELECTIONS
218 int sh = DfGetShift();
219 if (!(sh & (DF_LEFTSHIFT | DF_RIGHTSHIFT))) {
220 if (!(sh & DF_CTRLKEY))
221 ClearAllSelections(wnd);
222 wnd->AnchorPoint = sel;
223 DfSendMessage(wnd, DFM_PAINT, 0, 0);
224 }
225 #endif
226 DfSendMessage(wnd, DFM_LB_SELECTION, sel, TRUE);
227 py = my;
228 }
229 return TRUE;
230 }
231
232 /* ------------- DOUBLE_CLICK Message ------------ */
233 static int DoubleClickMsg(DFWINDOW wnd, DF_PARAM p1, DF_PARAM p2)
234 {
235 if (DfWindowMoving || DfWindowSizing)
236 return FALSE;
237 if (wnd->wlines) {
238 DFRECT rc = DfClientRect(wnd);
239 DfBaseWndProc(DF_LISTBOX, wnd, DOUBLE_CLICK, p1, p2);
240 if (DfInsideRect(p1, p2, rc))
241 DfSendMessage(wnd, DFM_LB_CHOOSE, wnd->selection, 0);
242 }
243 return TRUE;
244 }
245
246 /* ------------ DFM_ADDTEXT Message -------------- */
247 static int AddTextMsg(DFWINDOW wnd, DF_PARAM p1, DF_PARAM p2)
248 {
249 int rtn = DfBaseWndProc(DF_LISTBOX, wnd, DFM_ADDTEXT, p1, p2);
250 if (wnd->selection == -1)
251 DfSendMessage(wnd, DFM_LB_SETSELECTION, 0, 0);
252 #ifdef INCLUDE_EXTENDEDSELECTIONS
253 if (*(char *)p1 == DF_LISTSELECTOR)
254 wnd->SelectCount++;
255 #endif
256 return rtn;
257 }
258
259 /* --------- DFM_GETTEXT Message ------------ */
260 static void GetTextMsg(DFWINDOW wnd, DF_PARAM p1, DF_PARAM p2)
261 {
262 if ((int)p2 != -1) {
263 char *cp1 = (char *)p1;
264 char *cp2 = DfTextLine(wnd, (int)p2);
265 while (cp2 && *cp2 && *cp2 != '\n')
266 *cp1++ = *cp2++;
267 *cp1 = '\0';
268 }
269 }
270
271 /* --------- DF_LISTBOX Window Processing Module ------------ */
272 int DfListBoxProc(DFWINDOW wnd, DFMESSAGE msg, DF_PARAM p1, DF_PARAM p2)
273 {
274 switch (msg) {
275 case DFM_CREATE_WINDOW:
276 DfBaseWndProc(DF_LISTBOX, wnd, msg, p1, p2);
277 wnd->selection = -1;
278 #ifdef INCLUDE_EXTENDEDSELECTIONS
279 wnd->AnchorPoint = -1;
280 #endif
281 return TRUE;
282 case DFM_KEYBOARD:
283 if (DfWindowMoving || DfWindowSizing)
284 break;
285 if (KeyboardMsg(wnd, p1, p2))
286 return TRUE;
287 break;
288 case DFM_LEFT_BUTTON:
289 if (LeftButtonMsg(wnd, p1, p2) == TRUE)
290 return TRUE;
291 break;
292 case DOUBLE_CLICK:
293 if (DoubleClickMsg(wnd, p1, p2))
294 return TRUE;
295 break;
296 case DFM_BUTTON_RELEASED:
297 if (DfWindowMoving || DfWindowSizing || DfVSliding)
298 break;
299 py = -1;
300 return TRUE;
301 case DFM_ADDTEXT:
302 return AddTextMsg(wnd, p1, p2);
303 case DFM_LB_GETTEXT:
304 GetTextMsg(wnd, p1, p2);
305 return TRUE;
306 case DFM_CLEARTEXT:
307 wnd->selection = -1;
308 #ifdef INCLUDE_EXTENDEDSELECTIONS
309 wnd->AnchorPoint = -1;
310 #endif
311 wnd->SelectCount = 0;
312 break;
313 case DFM_PAINT:
314 DfBaseWndProc(DF_LISTBOX, wnd, msg, p1, p2);
315 WriteSelection(wnd, wnd->selection, TRUE, (DFRECT *)p1);
316 return TRUE;
317 case DFM_SCROLL:
318 case DFM_HORIZSCROLL:
319 case DFM_SCROLLPAGE:
320 case DFM_HORIZPAGE:
321 case DFM_SCROLLDOC:
322 DfBaseWndProc(DF_LISTBOX, wnd, msg, p1, p2);
323 WriteSelection(wnd,wnd->selection,TRUE,NULL);
324 return TRUE;
325 case DFM_LB_CHOOSE:
326 DfSendMessage(DfGetParent(wnd), DFM_LB_CHOOSE, p1, p2);
327 return TRUE;
328 case DFM_LB_SELECTION:
329 ChangeSelection(wnd, (int) p1, (int) p2);
330 DfSendMessage(DfGetParent(wnd), DFM_LB_SELECTION,
331 wnd->selection, 0);
332 return TRUE;
333 case DFM_LB_CURRENTSELECTION:
334 return wnd->selection;
335 case DFM_LB_SETSELECTION:
336 ChangeSelection(wnd, (int) p1, 0);
337 return TRUE;
338 #ifdef INCLUDE_EXTENDEDSELECTIONS
339 case DFM_CLOSE_WINDOW:
340 if (DfIsMultiLine(wnd) && wnd->AddMode) {
341 wnd->AddMode = FALSE;
342 DfSendMessage(DfGetParent(wnd), DFM_ADDSTATUS, 0, 0);
343 }
344 break;
345 #endif
346 default:
347 break;
348 }
349 return DfBaseWndProc(DF_LISTBOX, wnd, msg, p1, p2);
350 }
351
352 static BOOL SelectionInWindow(DFWINDOW wnd, int sel)
353 {
354 return (wnd->wlines && sel >= wnd->wtop &&
355 sel < wnd->wtop+DfClientHeight(wnd));
356 }
357
358 static void WriteSelection(DFWINDOW wnd, int sel,
359 int reverse, DFRECT *rc)
360 {
361 if (DfIsVisible(wnd))
362 if (SelectionInWindow(wnd, sel))
363 DfWriteTextLine(wnd, rc, sel, reverse);
364 }
365
366 #ifdef INCLUDE_EXTENDEDSELECTIONS
367 /* ----- Test for extended selections in the listbox ----- */
368 static void TestExtended(DFWINDOW wnd, DF_PARAM p2)
369 {
370 if (DfIsMultiLine(wnd) && !wnd->AddMode &&
371 !((int) p2 & (DF_LEFTSHIFT | DF_RIGHTSHIFT))) {
372 if (wnd->SelectCount > 1) {
373 ClearAllSelections(wnd);
374 DfSendMessage(wnd, DFM_PAINT, 0, 0);
375 }
376 }
377 }
378
379 /* ----- Clear selections in the listbox ----- */
380 static void ClearAllSelections(DFWINDOW wnd)
381 {
382 if (DfIsMultiLine(wnd) && wnd->SelectCount > 0) {
383 int sel;
384 for (sel = 0; sel < wnd->wlines; sel++)
385 ClearSelection(wnd, sel);
386 }
387 }
388
389 /* ----- Invert a selection in the listbox ----- */
390 static void FlipSelection(DFWINDOW wnd, int sel)
391 {
392 if (DfIsMultiLine(wnd)) {
393 if (DfItemSelected(wnd, sel))
394 ClearSelection(wnd, sel);
395 else
396 SetSelection(wnd, sel);
397 }
398 }
399
400 static int ExtendSelections(DFWINDOW wnd, int sel, int shift)
401 {
402 if (shift & (DF_LEFTSHIFT | DF_RIGHTSHIFT) &&
403 wnd->AnchorPoint != -1) {
404 int i = sel;
405 int j = wnd->AnchorPoint;
406 int rtn;
407 if (j > i)
408 swap(i,j);
409 rtn = i - j;
410 while (j <= i)
411 SetSelection(wnd, j++);
412 return rtn;
413 }
414 return 0;
415 }
416
417 static void SetSelection(DFWINDOW wnd, int sel)
418 {
419 if (DfIsMultiLine(wnd) && !DfItemSelected(wnd, sel)) {
420 char *lp = DfTextLine(wnd, sel);
421 *lp = DF_LISTSELECTOR;
422 wnd->SelectCount++;
423 }
424 }
425
426 static void ClearSelection(DFWINDOW wnd, int sel)
427 {
428 if (DfIsMultiLine(wnd) && DfItemSelected(wnd, sel)) {
429 char *lp = DfTextLine(wnd, sel);
430 *lp = ' ';
431 --wnd->SelectCount;
432 }
433 }
434
435 BOOL DfItemSelected(DFWINDOW wnd, int sel)
436 {
437 if (sel != -1 && DfIsMultiLine(wnd) && sel < wnd->wlines) {
438 char *cp = DfTextLine(wnd, sel);
439 return (int)((*cp) & 255) == DF_LISTSELECTOR;
440 }
441 return FALSE;
442 }
443 #endif
444
445 static void ChangeSelection(DFWINDOW wnd,int sel,int shift)
446 {
447 if (sel != wnd->selection) {
448 #ifdef INCLUDE_EXTENDEDSELECTIONS
449 if (DfIsMultiLine(wnd)) {
450 int sels;
451 if (!wnd->AddMode)
452 ClearAllSelections(wnd);
453 sels = ExtendSelections(wnd, sel, shift);
454 if (sels > 1)
455 DfSendMessage(wnd, DFM_PAINT, 0, 0);
456 if (sels == 0 && !wnd->AddMode) {
457 ClearSelection(wnd, wnd->selection);
458 SetSelection(wnd, sel);
459 wnd->AnchorPoint = sel;
460 }
461 }
462 #endif
463 WriteSelection(wnd, wnd->selection, FALSE, NULL);
464 wnd->selection = sel;
465 WriteSelection(wnd, sel, TRUE, NULL);
466 }
467 }
468
469 /* EOF */