AmendHub

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 }