Download
jcs
/amend
/browser.c
(View History)
jcs committer: Add Command+W shortcut to cancel commit | Latest amendment: 103 on 2022-09-12 |
1 | /* |
2 | * Copyright (c) 2021-2022 joshua stein <jcs@jcs.org> |
3 | * |
4 | * Permission to use, copy, modify, and distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above |
6 | * copyright notice and this permission notice appear in all copies. |
7 | * |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ |
16 | |
17 | #include <stdarg.h> |
18 | #include <stdio.h> |
19 | #include <string.h> |
20 | |
21 | #include "amend.h" |
22 | #include "browser.h" |
23 | #include "committer.h" |
24 | #include "diff.h" |
25 | #include "editor.h" |
26 | #include "focusable.h" |
27 | #include "patch.h" |
28 | #include "repo.h" |
29 | #include "settings.h" |
30 | #include "tetab.h" |
31 | #include "util.h" |
32 | |
33 | #define FILE_LIST_FONT geneva |
34 | #define FILE_LIST_FONT_SIZE 10 |
35 | #define DIFF_BUTTON_FONT geneva |
36 | #define DIFF_BUTTON_FONT_SIZE 12 |
37 | |
38 | #define PADDING 10 |
39 | |
40 | bool browser_close(struct focusable *focusable); |
41 | void browser_idle(struct focusable *focusable, EventRecord *event); |
42 | void browser_update_menu(struct browser *browser); |
43 | void browser_update(struct focusable *focusable, EventRecord *event); |
44 | void browser_show_amendment(struct browser *browser, |
45 | struct repo_amendment *amendment); |
46 | void browser_mouse_down(struct focusable *focusable, EventRecord *event); |
47 | bool browser_handle_menu(struct focusable *focusable, short menu, |
48 | short item); |
49 | |
50 | void browser_add_files(struct browser *browser); |
51 | void browser_filter_amendments(struct browser *browser); |
52 | void browser_discard_changes(struct browser *browser); |
53 | void browser_edit_amendment(struct browser *browser); |
54 | |
55 | Pattern fill_pattern; |
56 | |
57 | void |
58 | browser_idle(struct focusable *focusable, EventRecord *event) |
59 | { |
60 | struct browser *browser = (struct browser *)focusable->cookie; |
61 | |
62 | switch (browser->state) { |
63 | case BROWSER_STATE_IDLE: |
64 | if (browser->need_refresh) { |
65 | browser->need_refresh = false; |
66 | browser->state = BROWSER_STATE_UPDATE_AMENDMENT_LIST; |
67 | } |
68 | break; |
69 | case BROWSER_STATE_ADD_FILE: |
70 | if (repo_add_file(browser->repo) == NULL) |
71 | browser->state = BROWSER_STATE_IDLE; |
72 | else |
73 | browser->state = BROWSER_STATE_UPDATE_FILE_LIST; |
74 | break; |
75 | case BROWSER_STATE_UPDATE_FILE_LIST: |
76 | browser_add_files(browser); |
77 | browser->state = BROWSER_STATE_IDLE; |
78 | break; |
79 | case BROWSER_STATE_UPDATE_AMENDMENT_LIST: |
80 | browser_filter_amendments(browser); |
81 | browser->state = BROWSER_STATE_IDLE; |
82 | break; |
83 | case BROWSER_STATE_OPEN_COMMITTER: |
84 | committer_init(browser); |
85 | browser->state = BROWSER_STATE_WAITING_FOR_COMMITTER; |
86 | break; |
87 | case BROWSER_STATE_WAITING_FOR_COMMITTER: |
88 | break; |
89 | case BROWSER_STATE_DISCARD_CHANGES: |
90 | browser_discard_changes(browser); |
91 | browser->state = BROWSER_STATE_IDLE; |
92 | break; |
93 | case BROWSER_STATE_EXPORT_PATCH: |
94 | browser_export_patch(browser); |
95 | browser->state = BROWSER_STATE_IDLE; |
96 | break; |
97 | case BROWSER_STATE_APPLY_PATCH: |
98 | browser_apply_patch(browser); |
99 | browser->state = BROWSER_STATE_IDLE; |
100 | break; |
101 | case BROWSER_STATE_EDIT_AMENDMENT: |
102 | browser_edit_amendment(browser); |
103 | browser->state = BROWSER_STATE_IDLE; |
104 | break; |
105 | } |
106 | } |
107 | |
108 | struct browser * |
109 | browser_init(struct repo *repo) |
110 | { |
111 | char title[256], filename[256], *justfilename; |
112 | struct browser *browser; |
113 | struct focusable *focusable; |
114 | Rect bounds = { 0 }, te_bounds = { 0 }; |
115 | Rect data_bounds = { 0, 0, 0, 1 }; /* tlbr */ |
116 | Point cell_size = { 0, 0 }; |
117 | Cell cell = { 0 }; |
118 | short colonpos, n, width, height; |
119 | |
120 | browser = xmalloczero(sizeof(struct browser), "browser"); |
121 | browser->state = BROWSER_STATE_IDLE; |
122 | browser->repo = repo; |
123 | |
124 | GetIndPattern(&fill_pattern, sysPatListID, 22); |
125 | |
126 | /* main window */ |
127 | width = screenBits.bounds.right - screenBits.bounds.left - PADDING; |
128 | if (width > 540) |
129 | width = 540; |
130 | height = screenBits.bounds.bottom - screenBits.bounds.top - |
131 | PADDING - (GetMBarHeight() * 2); |
132 | if (height > 350) |
133 | height = 350; |
134 | center_in_screen(width, height, true, &bounds); |
135 | |
136 | memcpy(filename, browser->repo->bile->filename, sizeof(filename)); |
137 | PtoCstr(filename); |
138 | justfilename = strrchr(filename, ':'); |
139 | if (justfilename == NULL) |
140 | justfilename = (char *)&filename; |
141 | else |
142 | justfilename++; |
143 | snprintf(title, sizeof(title), "%s: %s", PROGRAM_NAME, justfilename); |
144 | CtoPstr(title); |
145 | browser->win = NewWindow(0L, &bounds, title, false, noGrowDocProc, |
146 | (WindowPtr)-1L, true, 0); |
147 | if (!browser->win) |
148 | err(1, "Can't create window"); |
149 | SetPort(browser->win); |
150 | |
151 | /* file list */ |
152 | bounds.top = bounds.left = PADDING; |
153 | bounds.bottom = browser->win->portRect.bottom - |
154 | (browser->win->portRect.bottom * 0.6) - 2 - 20 - PADDING - PADDING; |
155 | bounds.right = 100; |
156 | |
157 | TextFont(FILE_LIST_FONT); |
158 | TextSize(FILE_LIST_FONT_SIZE); |
159 | browser->file_list = LNew(&bounds, &data_bounds, cell_size, 0, |
160 | browser->win, true, true, false, true); |
161 | if (!browser->file_list) |
162 | err(1, "Can't create file list"); |
163 | LAddColumn(1, 0, browser->file_list); |
164 | (*(browser->file_list))->selFlags = lNoNilHilite; |
165 | |
166 | /* diff button */ |
167 | bounds.top = bounds.bottom + PADDING; |
168 | bounds.bottom = bounds.top + 20; |
169 | bounds.right += SCROLLBAR_WIDTH; |
170 | TextFont(DIFF_BUTTON_FONT); |
171 | TextSize(DIFF_BUTTON_FONT_SIZE); |
172 | browser->diff_button = NewControl(browser->win, &bounds, |
173 | "\pGenerate Diff", true, 1, 1, 1, pushButProc | useWFont, 0L); |
174 | |
175 | /* amendment list */ |
176 | bounds.top = bounds.left = PADDING; |
177 | bounds.left = bounds.right + PADDING; |
178 | bounds.right = browser->win->portRect.right - SCROLLBAR_WIDTH - PADDING; |
179 | |
180 | cell_size.v = (FontHeight(geneva, 9) * 2) + 2; |
181 | browser->amendment_list = LNew(&bounds, &data_bounds, cell_size, |
182 | AMENDMENT_LDEF_ID, browser->win, true, true, false, true); |
183 | if (!browser->amendment_list) |
184 | err(1, "Can't create amendment list"); |
185 | LAddColumn(1, 0, browser->amendment_list); |
186 | (*(browser->amendment_list))->selFlags = lOnlyOne; |
187 | |
188 | /* diff text */ |
189 | bounds.top = (*browser->amendment_list)->rView.bottom + PADDING; |
190 | bounds.left = PADDING; |
191 | bounds.right = browser->win->portRect.right - SCROLLBAR_WIDTH - PADDING; |
192 | bounds.bottom = browser->win->portRect.bottom - PADDING; |
193 | te_bounds = bounds; |
194 | InsetRect(&te_bounds, 2, 2); |
195 | browser->diff_te = TEStylNew(&te_bounds, &bounds); |
196 | TEAutoView(true, browser->diff_te); |
197 | TETabEnable(browser->diff_te); |
198 | (*(browser->diff_te))->caretHook = NullCaretHook; |
199 | TEActivate(browser->diff_te); |
200 | |
201 | /* scrollbar for diff text */ |
202 | bounds.right = browser->win->portRect.right - PADDING; |
203 | bounds.left = bounds.right - SCROLLBAR_WIDTH; |
204 | bounds.bottom++; |
205 | bounds.top--; |
206 | browser->diff_scroller = NewControl(browser->win, &bounds, "\p", true, |
207 | 1, 1, 1, scrollBarProc, 0L); |
208 | |
209 | browser_update_menu(browser); |
210 | browser_add_files(browser); |
211 | UpdateScrollbarForTE(browser->win, browser->diff_scroller, |
212 | browser->diff_te, true); |
213 | |
214 | focusable = xmalloczero(sizeof(struct focusable), "focusable"); |
215 | focusable->cookie = browser; |
216 | focusable->win = browser->win; |
217 | focusable->idle = browser_idle; |
218 | focusable->update = browser_update; |
219 | focusable->mouse_down = browser_mouse_down; |
220 | focusable->menu = browser_handle_menu; |
221 | focusable->close = browser_close; |
222 | focusable_add(focusable); |
223 | |
224 | progress(NULL); |
225 | |
226 | return browser; |
227 | } |
228 | |
229 | bool |
230 | browser_close(struct focusable *focusable) |
231 | { |
232 | struct browser *browser = (struct browser *)focusable->cookie; |
233 | |
234 | if (browser->committer) |
235 | browser_close_committer(browser); |
236 | |
237 | if (browser->repo) |
238 | repo_close(browser->repo); |
239 | |
240 | TEDispose(browser->diff_te); |
241 | DisposeWindow(browser->win); |
242 | |
243 | xfree(&browser); |
244 | |
245 | menu_defaults(); |
246 | |
247 | return true; |
248 | } |
249 | |
250 | void |
251 | browser_close_committer(struct browser *browser) |
252 | { |
253 | struct focusable *f; |
254 | |
255 | if (browser->committer) { |
256 | f = focusable_find(browser->committer->win); |
257 | if (f) |
258 | focusable_close(f); |
259 | } |
260 | } |
261 | |
262 | void |
263 | browser_add_files(struct browser *browser) |
264 | { |
265 | char filename[256]; |
266 | Cell cell = { 0, 0 }; |
267 | short i; |
268 | |
269 | LDoDraw(false, browser->file_list); |
270 | LDelRow(0, 0, browser->file_list); |
271 | browser_show_amendment(browser, NULL); |
272 | |
273 | TextFont(FILE_LIST_FONT); |
274 | TextSize(FILE_LIST_FONT_SIZE); |
275 | LAddRow(1, cell.v, browser->file_list); |
276 | LSetCell("[All Files]", 11, cell, browser->file_list); |
277 | LSetSelect(true, cell, browser->file_list); |
278 | cell.v++; |
279 | |
280 | /* fill in files */ |
281 | for (i = 0; i < browser->repo->nfiles; i++) { |
282 | LAddRow(1, cell.v, browser->file_list); |
283 | if (browser->repo->files[i]->flags & REPO_FILE_DELETED) |
284 | snprintf(filename, sizeof(filename), "~%s~", |
285 | browser->repo->files[i]->filename); |
286 | else |
287 | strlcpy(filename, browser->repo->files[i]->filename, |
288 | sizeof(filename)); |
289 | LSetCell(&filename, strlen(filename), cell, browser->file_list); |
290 | cell.v++; |
291 | } |
292 | |
293 | LDoDraw(true, browser->file_list); |
294 | |
295 | browser_filter_amendments(browser); |
296 | InvalRect(&browser->win->portRect); |
297 | } |
298 | |
299 | short |
300 | browser_is_all_files_selected(struct browser *browser) |
301 | { |
302 | Cell cell = { 0 }; |
303 | |
304 | if (browser->repo->nfiles == 0) |
305 | return 0; |
306 | |
307 | /* |
308 | * "All Files" is always cell.v=0, so if v=0 is selected or nothing |
309 | * is, select all files |
310 | */ |
311 | if (LGetSelect(false, &cell, browser->file_list) == true || |
312 | LGetSelect(true, &cell, browser->file_list) == false) |
313 | return 1; |
314 | |
315 | return 0; |
316 | } |
317 | |
318 | short |
319 | browser_selected_file_ids(struct browser *browser, short **selected_files) |
320 | { |
321 | Cell cell = { 0 }; |
322 | short nselected_files = 0, i; |
323 | |
324 | if (browser->repo->nfiles == 0) { |
325 | *selected_files = NULL; |
326 | return 0; |
327 | } |
328 | |
329 | *selected_files = xcalloc(browser->repo->nfiles, sizeof(short), |
330 | "selected_files"); |
331 | |
332 | if (browser_is_all_files_selected(browser)) { |
333 | nselected_files = browser->repo->nfiles; |
334 | for (i = 0; i < browser->repo->nfiles; i++) |
335 | (*selected_files)[i] = browser->repo->files[i]->id; |
336 | } else { |
337 | cell.v = 0; |
338 | while (LGetSelect(true, &cell, browser->file_list)) { |
339 | (*selected_files)[nselected_files] = |
340 | browser->repo->files[cell.v - 1]->id; |
341 | nselected_files++; |
342 | LNextCell(true, true, &cell, browser->file_list); |
343 | } |
344 | } |
345 | |
346 | return nselected_files; |
347 | } |
348 | |
349 | void |
350 | browser_filter_amendments(struct browser *browser) |
351 | { |
352 | Cell cell = { 0 }; |
353 | struct repo_amendment *amendment; |
354 | short i, j, k, add = 0, file_id; |
355 | short *selected_files = NULL; |
356 | short nselected_files = 0; |
357 | |
358 | LDoDraw(false, browser->amendment_list); |
359 | LDelRow(0, 0, browser->amendment_list); |
360 | browser_show_amendment(browser, NULL); |
361 | |
362 | /* fill in amendments for selected files */ |
363 | nselected_files = browser_selected_file_ids(browser, &selected_files); |
364 | cell.v = 0; |
365 | for (i = 0; i < browser->repo->namendments; i++) { |
366 | add = 0; |
367 | amendment = browser->repo->amendments[i]; |
368 | for (j = 0; j < amendment->nfiles; j++) { |
369 | file_id = amendment->file_ids[j]; |
370 | for (k = 0; k < nselected_files; k++) { |
371 | if (selected_files[k] == amendment->file_ids[j]) { |
372 | add = 1; |
373 | break; |
374 | } |
375 | } |
376 | if (add) |
377 | break; |
378 | } |
379 | |
380 | if (!add) |
381 | continue; |
382 | |
383 | LAddRow(1, cell.v, browser->amendment_list); |
384 | LSetCell(&(browser->repo->amendments[i]), sizeof(Ptr), cell, |
385 | browser->amendment_list); |
386 | cell.v++; |
387 | } |
388 | |
389 | LDoDraw(true, browser->amendment_list); |
390 | InvalRect(&(*(browser->amendment_list))->rView); |
391 | |
392 | if (selected_files) |
393 | xfree(&selected_files); |
394 | } |
395 | |
396 | void |
397 | browser_show_amendment(struct browser *browser, |
398 | struct repo_amendment *amendment) |
399 | { |
400 | struct repo_diff *diff; |
401 | |
402 | if (amendment == NULL) { |
403 | TESetText("", 0, browser->diff_te); |
404 | HLock(browser->diff_te); |
405 | InvalRect(&(*(browser->diff_te))->viewRect); |
406 | HUnlock(browser->diff_te); |
407 | } else { |
408 | SetCursor(*(GetCursor(watchCursor))); |
409 | repo_show_diff_text(browser->repo, amendment, browser->diff_te); |
410 | SetCursor(&arrow); |
411 | } |
412 | |
413 | UpdateScrollbarForTE(browser->win, browser->diff_scroller, |
414 | browser->diff_te, true); |
415 | browser_update_menu(browser); |
416 | } |
417 | |
418 | void |
419 | browser_discard_changes(struct browser *browser) |
420 | { |
421 | char buf[256], filename[256]; |
422 | struct repo_file *file; |
423 | short *selected = NULL; |
424 | short nselected = 0, i, error; |
425 | SFReply reply; |
426 | |
427 | nselected = browser_selected_file_ids(browser, &selected); |
428 | for (i = 0; i < nselected; i++) { |
429 | file = repo_file_with_id(browser->repo, selected[i]); |
430 | |
431 | snprintf(buf, sizeof(buf), "Save %s:", file->filename); |
432 | CtoPstr(buf); |
433 | |
434 | strlcpy(filename, file->filename, sizeof(filename)); |
435 | CtoPstr(filename); |
436 | |
437 | SFPutFile(centered_sfput_dialog(), buf, filename, NULL, &reply); |
438 | if (!reply.good) |
439 | break; |
440 | |
441 | error = repo_checkout_file(browser->repo, file, reply.vRefNum, |
442 | reply.fName); |
443 | if (error) |
444 | break; |
445 | } |
446 | } |
447 | |
448 | void |
449 | browser_export_patch(struct browser *browser) |
450 | { |
451 | Cell selected = { 0 }; |
452 | struct repo_amendment *amendment; |
453 | short error, len; |
454 | SFReply reply; |
455 | |
456 | if (LGetSelect(true, &selected, browser->amendment_list) == false) |
457 | return; |
458 | |
459 | len = sizeof(Ptr); |
460 | LGetCell(&amendment, &len, selected, browser->amendment_list); |
461 | |
462 | SFPutFile(centered_sfput_dialog(), "\pSave patch as:", NULL, NULL, |
463 | &reply); |
464 | if (!reply.good) |
465 | return; |
466 | |
467 | repo_export_patch(browser->repo, amendment, reply.vRefNum, reply.fName); |
468 | } |
469 | |
470 | void |
471 | browser_apply_patch(struct browser *browser) |
472 | { |
473 | SFReply reply; |
474 | |
475 | SFGetFile(centered_sfget_dialog(), NULL, NULL, -1, NULL, NULL, &reply); |
476 | if (!reply.good) |
477 | return; |
478 | |
479 | patch_process(browser->repo, reply.fName, reply.vRefNum); |
480 | } |
481 | |
482 | void |
483 | browser_edit_amendment(struct browser *browser) |
484 | { |
485 | Point pt = { 75, 100 }; |
486 | Cell selected = { 0 }; |
487 | struct repo_amendment *amendment; |
488 | short error, len; |
489 | SFReply reply; |
490 | |
491 | if (LGetSelect(true, &selected, browser->amendment_list) == false) |
492 | return; |
493 | |
494 | len = sizeof(Ptr); |
495 | LGetCell(&amendment, &len, selected, browser->amendment_list); |
496 | |
497 | editor_init(browser, amendment); |
498 | } |
499 | |
500 | void |
501 | browser_update_menu(struct browser *browser) |
502 | { |
503 | size_t vlines; |
504 | TERec *diff; |
505 | Cell cell = { 0, 0 }; |
506 | |
507 | TextFont(systemFont); |
508 | TextSize(12); |
509 | |
510 | HLock(browser->diff_te); |
511 | diff = *(browser->diff_te); |
512 | |
513 | DisableItem(edit_menu, EDIT_MENU_CUT_ID); |
514 | |
515 | if (diff->selStart == diff->selEnd) |
516 | DisableItem(edit_menu, EDIT_MENU_COPY_ID); |
517 | else |
518 | EnableItem(edit_menu, EDIT_MENU_COPY_ID); |
519 | |
520 | DisableItem(edit_menu, EDIT_MENU_PASTE_ID); |
521 | |
522 | if (diff->nLines == 0) |
523 | DisableItem(edit_menu, EDIT_MENU_SELECT_ALL_ID); |
524 | else |
525 | EnableItem(edit_menu, EDIT_MENU_SELECT_ALL_ID); |
526 | |
527 | HUnlock(browser->diff_te); |
528 | |
529 | if (browser->repo->nfiles == 0) |
530 | HiliteControl(browser->diff_button, 255); |
531 | else |
532 | HiliteControl(browser->diff_button, 0); |
533 | |
534 | if (!browser->committer) { |
535 | EnableItem(repo_menu, REPO_MENU_ADD_FILE_ID); |
536 | EnableItem(repo_menu, REPO_MENU_DISCARD_CHANGES_ID); |
537 | #if 0 |
538 | EnableItem(repo_menu, REPO_MENU_APPLY_PATCH_ID); |
539 | #endif |
540 | } |
541 | |
542 | if (LGetSelect(true, &cell, browser->amendment_list)) { |
543 | EnableItem(amendment_menu, AMENDMENT_MENU_EDIT_ID); |
544 | EnableItem(amendment_menu, AMENDMENT_MENU_EXPORT_ID); |
545 | } else { |
546 | DisableItem(amendment_menu, AMENDMENT_MENU_EDIT_ID); |
547 | DisableItem(amendment_menu, AMENDMENT_MENU_EXPORT_ID); |
548 | } |
549 | } |
550 | |
551 | void |
552 | browser_update(struct focusable *focusable, EventRecord *event) |
553 | { |
554 | struct browser *browser = (struct browser *)focusable->cookie; |
555 | Str255 buf; |
556 | Rect r; |
557 | short what = -1; |
558 | |
559 | if (event != NULL) |
560 | what = event->what; |
561 | |
562 | switch (what) { |
563 | case -1: |
564 | case updateEvt: |
565 | FillRect(&browser->win->portRect, fill_pattern); |
566 | |
567 | r = (*(browser->diff_te))->viewRect; |
568 | FillRect(&r, white); |
569 | TEUpdate(&r, browser->diff_te); |
570 | InsetRect(&r, -1, -1); |
571 | FrameRect(&r); |
572 | |
573 | r = (*(browser->file_list))->rView; |
574 | InsetRect(&r, -1, -1); |
575 | FillRect(&r, white); |
576 | FrameRect(&r); |
577 | TextFont(FILE_LIST_FONT); |
578 | TextSize(FILE_LIST_FONT_SIZE); |
579 | LUpdate(browser->win->visRgn, browser->file_list); |
580 | |
581 | r = (*(browser->amendment_list))->rView; |
582 | InsetRect(&r, -1, -1); |
583 | FillRect(&r, white); |
584 | FrameRect(&r); |
585 | LUpdate(browser->win->visRgn, browser->amendment_list); |
586 | |
587 | TextFont(DIFF_BUTTON_FONT); |
588 | TextSize(DIFF_BUTTON_FONT_SIZE); |
589 | UpdtControl(browser->win, browser->win->visRgn); |
590 | |
591 | browser_update_menu(browser); |
592 | |
593 | break; |
594 | } |
595 | } |
596 | |
597 | void |
598 | browser_mouse_down(struct focusable *focusable, EventRecord *event) |
599 | { |
600 | Cell selected = { 0 }, now = { 0 }; |
601 | Point p; |
602 | ControlHandle control; |
603 | Rect r; |
604 | struct browser *browser = (struct browser *)focusable->cookie; |
605 | struct repo_amendment *amendment = NULL; |
606 | short *selected_files = NULL, *now_selected_files = NULL; |
607 | short nselected = 0, nnow_selected = 0; |
608 | short val, adj, page, was_selected, part, i, data_len; |
609 | char *path; |
610 | |
611 | p = event->where; |
612 | GlobalToLocal(&p); |
613 | |
614 | /* is it in diff text? */ |
615 | r = (*(browser->diff_te))->viewRect; |
616 | if (PtInRect(p, &r)) { |
617 | TEClick(p, ((event->modifiers & shiftKey) != 0), browser->diff_te); |
618 | browser_update_menu(browser); |
619 | return; |
620 | } |
621 | |
622 | /* is it in file list? */ |
623 | r = (*(browser->file_list))->rView; |
624 | r.right += SCROLLBAR_WIDTH; |
625 | if (PtInRect(p, &r)) { |
626 | /* store what is selected now */ |
627 | nselected = browser_selected_file_ids(browser, &selected_files); |
628 | |
629 | /* in case any new items are redrawn in LClick */ |
630 | TextFont(FILE_LIST_FONT); |
631 | TextSize(FILE_LIST_FONT_SIZE); |
632 | |
633 | /* possibly highlight a new cell */ |
634 | LClick(p, event->modifiers, browser->file_list); |
635 | |
636 | nnow_selected = browser_selected_file_ids(browser, |
637 | &now_selected_files); |
638 | |
639 | if (nnow_selected == 0) { |
640 | /* can't select nothing, select 'all files' */ |
641 | selected.v = 0; |
642 | LSetSelect(true, selected, browser->file_list); |
643 | if (nselected != browser->repo->nfiles) |
644 | browser_filter_amendments(browser); |
645 | } else if (nselected != nnow_selected) { |
646 | browser_filter_amendments(browser); |
647 | } else { |
648 | for (i = 0; i < nselected; i++) { |
649 | if (selected_files[i] != now_selected_files[i]) { |
650 | browser_filter_amendments(browser); |
651 | break; |
652 | } |
653 | } |
654 | } |
655 | |
656 | if (selected_files) |
657 | xfree(&selected_files); |
658 | if (now_selected_files) |
659 | xfree(&now_selected_files); |
660 | |
661 | return; |
662 | } |
663 | |
664 | /* is it in amendment list? */ |
665 | r = (*(browser->amendment_list))->rView; |
666 | r.right += SCROLLBAR_WIDTH; |
667 | if (PtInRect(p, &r)) { |
668 | if (browser->repo == NULL) |
669 | return; |
670 | |
671 | /* store what is selected now */ |
672 | was_selected = LGetSelect(true, &selected, browser->amendment_list); |
673 | |
674 | /* possibly highlight a new cell */ |
675 | LClick(p, event->modifiers, browser->amendment_list); |
676 | |
677 | if (LGetSelect(true, &now, browser->amendment_list) == false) { |
678 | if (was_selected) |
679 | browser_show_amendment(browser, NULL); |
680 | } else if (!was_selected || selected.v != now.v) { |
681 | if (was_selected) |
682 | LSetSelect(false, selected, browser->amendment_list); |
683 | LSetSelect(true, now, browser->amendment_list); |
684 | |
685 | /* in a filtered list, amendments[now.v] won't be accurate */ |
686 | data_len = sizeof(Ptr); |
687 | LGetCell(&amendment, &data_len, now, browser->amendment_list); |
688 | browser_show_amendment(browser, amendment); |
689 | } |
690 | |
691 | return; |
692 | } |
693 | |
694 | switch (part = FindControl(p, browser->win, &control)) { |
695 | case inButton: |
696 | TextFont(DIFF_BUTTON_FONT); |
697 | TextSize(DIFF_BUTTON_FONT_SIZE); |
698 | if (TrackControl(control, p, 0L) && |
699 | control == browser->diff_button) |
700 | browser->state = BROWSER_STATE_OPEN_COMMITTER; |
701 | break; |
702 | case inUpButton: |
703 | case inDownButton: |
704 | case inPageUp: |
705 | case inPageDown: |
706 | if (control == browser->diff_scroller) |
707 | SetTrackControlTE(browser->diff_te); |
708 | else |
709 | break; |
710 | TrackControl(control, p, TrackMouseDownInControl); |
711 | break; |
712 | case inThumb: |
713 | val = GetCtlValue(control); |
714 | if (TrackControl(control, p, 0L) == 0) |
715 | break; |
716 | adj = val - GetCtlValue(control); |
717 | if (adj != 0) { |
718 | val -= adj; |
719 | if (control == browser->diff_scroller) |
720 | TEScroll(0, adj * TEGetHeight(0, 0, browser->diff_te), |
721 | browser->diff_te); |
722 | SetCtlValue(control, val); |
723 | } |
724 | break; |
725 | } |
726 | } |
727 | |
728 | bool |
729 | browser_handle_menu(struct focusable *focusable, short menu, short item) |
730 | { |
731 | struct browser *browser = (struct browser *)focusable->cookie; |
732 | |
733 | switch (menu) { |
734 | case EDIT_MENU_ID: |
735 | switch (item) { |
736 | case EDIT_MENU_COPY_ID: |
737 | TECopy(browser->diff_te); |
738 | return true; |
739 | case EDIT_MENU_SELECT_ALL_ID: |
740 | TESetSelect(0, 1024 * 32, browser->diff_te); |
741 | return true; |
742 | } |
743 | break; |
744 | case REPO_MENU_ID: |
745 | switch (item) { |
746 | case REPO_MENU_ADD_FILE_ID: |
747 | browser->state = BROWSER_STATE_ADD_FILE; |
748 | return true; |
749 | case REPO_MENU_DISCARD_CHANGES_ID: |
750 | browser->state = BROWSER_STATE_DISCARD_CHANGES; |
751 | return true; |
752 | case REPO_MENU_APPLY_PATCH_ID: |
753 | browser->state = BROWSER_STATE_APPLY_PATCH; |
754 | return true; |
755 | } |
756 | break; |
757 | case AMENDMENT_MENU_ID: |
758 | switch (item) { |
759 | case AMENDMENT_MENU_EDIT_ID: |
760 | browser->state = BROWSER_STATE_EDIT_AMENDMENT; |
761 | return true; |
762 | case AMENDMENT_MENU_EXPORT_ID: |
763 | browser->state = BROWSER_STATE_EXPORT_PATCH; |
764 | return true; |
765 | } |
766 | break; |
767 | } |
768 | |
769 | return false; |
770 | } |