AmendHub

Download

jcs

/

amend

/

browser.c

 

(View History)

jcs   repo: Set cursor to watch while we're loading a repo Latest amendment: 118 on 2023-04-18

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