AmendHub

Download

jcs

/

amend

/

browser.c

 

(View History)

jcs   browser: Use a custom LDEF for file list to cross out deleted files Latest amendment: 253 on 2023-11-01

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