From 0b5ff711ccefc02250cc4a8dd2ea81c8c4421a34 Mon Sep 17 00:00:00 2001
From: echicken <>
Date: Tue, 5 May 2020 04:49:21 +0000
Subject: [PATCH] Mouse support.

---
 exec/avatar_chooser.js | 278 +++++++++++++++++++++--------------------
 1 file changed, 144 insertions(+), 134 deletions(-)

diff --git a/exec/avatar_chooser.js b/exec/avatar_chooser.js
index 50acf79c92..6b1cd40f76 100644
--- a/exec/avatar_chooser.js
+++ b/exec/avatar_chooser.js
@@ -8,10 +8,12 @@ load('event-timer.js');
 load('ansiedit.js');
 
 const sauce_lib = load({}, 'sauce_lib.js');
-if(bbs.mods.avatar_lib)
+if (bbs.mods.avatar_lib) {
 	avatar_lib = bbs.mods.avatar_lib;
-else
+} else {
 	avatar_lib = load({}, 'avatar_lib.js');
+}
+require("mouse_getkey.js", "mouse_getkey");
 const ansiterm = load({}, 'ansiterm_lib.js');
 
 const BORDER = [ BLUE, LIGHTBLUE, CYAN, LIGHTCYAN, WHITE ];
@@ -92,6 +94,11 @@ Frame.prototype.blit = function (bin, w, h, x, y, str, sc) {
 	}
 }
 
+function mouse_enable(enable) {
+	if (!console.term_supports(USER_ANSI)) return;
+	ansiterm.send('mouse', enable ? 'set' : 'clear', 'normal_tracking');
+}
+
 function bury_cursor() {
 	console.gotoxy(console.screen_columns, console.screen_rows);
 }
@@ -167,12 +174,10 @@ function CollectionBrowser(filename, parent_frame) {
 	}
 
 	function draw_collection(offset) {
-
 		const f = new File(filename);
 		f.open('rb');
 		const avatars = f.read();
 		f.close();
-
 		var x = 1, y = 2;
 		for (var a = 0; a < collection.count; a++) {
 			frames.container.blit(avatars.substr(a * avatar_lib.size, avatar_lib.size), avatar_lib.defs.width, avatar_lib.defs.height, x, y, collection.descriptions[a], WHITE);
@@ -182,9 +187,7 @@ function CollectionBrowser(filename, parent_frame) {
 				y += avatar_lib.defs.height + 2;
 			}
 		}
-
 		highlight();
-
 	}
 
 	function highlight() {
@@ -243,53 +246,79 @@ function CollectionBrowser(filename, parent_frame) {
 
 	this.getcmd = function (cmd) {
 		var ret = null;
-		switch (cmd.toLowerCase()) {
-			case KEY_LEFT:
+		if (cmd.mouse !== null && cmd.mouse.press && cmd.mouse.x >= frames.container.x && cmd.mouse.x < frames.container.x + frames.container.width && cmd.mouse.y >= frames.container.y && cmd.mouse.y < frames.container.y + frames.container.height) {
+			if (cmd.mouse.button == 0) {
+				var mx = cmd.mouse.x - frames.container.x;
+				var my = cmd.mouse.y - frames.container.y;
+				var mcol = Math.min(Math.floor(mx / (avatar_lib.defs.width + 2)), state.cols);
+				var mrow = Math.min(Math.floor(my / (avatar_lib.defs.height + 2)), state.rows);
+				var sel = (mcol + (state.cols * mrow));
+				if (sel < collection.count) {
+					state.selected = sel;
+					highlight();
+					flashy_flashy();
+					ret = state.selected;
+				}
+			} else if (cmd.mouse.button == 64) {
 				if (state.selected > 0) {
 					state.selected--;
 					highlight();
 				}
-				break;
-			case KEY_RIGHT:
+			} else if (cmd.mouse.button == 65) {
 				if (state.selected < collection.count - 1) {
 					state.selected++;
 					highlight();
 				}
-				break;
-			case KEY_UP:
-				if (state.selected - state.cols >= 0) {
-					state.selected -= state.cols;
-					highlight();
-				}
-				break;
-			case KEY_DOWN:
-				if (state.selected + state.cols < collection.count) {
-					state.selected += state.cols;
-					highlight();
-				}
-				break;
-            case KEY_HOME:
-                if (state.selected > 0) {
-                    state.selected = 0;
-                    highlight();
-                }
-                break;
-            case KEY_END:
-                if (state.selected < collection.count - 1) {
-                    state.selected = collection.count - 1;
-                    highlight();
-                }
-                break;
-			case '\r':
-			case '\n':
-				flashy_flashy();
-				ret = state.selected;
-				break;
-			case 'q':
-				ret = -1;
-				break;
-			default:
-				break;
+			}
+		} else {
+			switch (cmd.key.toLowerCase()) {
+				case KEY_LEFT:
+					if (state.selected > 0) {
+						state.selected--;
+						highlight();
+					}
+					break;
+				case KEY_RIGHT:
+					if (state.selected < collection.count - 1) {
+						state.selected++;
+						highlight();
+					}
+					break;
+				case KEY_UP:
+					if (state.selected - state.cols >= 0) {
+						state.selected -= state.cols;
+						highlight();
+					}
+					break;
+				case KEY_DOWN:
+					if (state.selected + state.cols < collection.count) {
+						state.selected += state.cols;
+						highlight();
+					}
+					break;
+				case KEY_HOME:
+					if (state.selected > 0) {
+						state.selected = 0;
+						highlight();
+					}
+					break;
+				case KEY_END:
+					if (state.selected < collection.count - 1) {
+						state.selected = collection.count - 1;
+						highlight();
+					}
+					break;
+				case '\r':
+				case '\n':
+					flashy_flashy();
+					ret = state.selected;
+					break;
+				case 'q':
+					ret = -1;
+					break;
+				default:
+					break;
+			}
 		}
 		return ret;
 	}
@@ -405,7 +434,7 @@ function CollectionLister(dir, parent_frame) {
 		state.tree.colors.kfg = LIGHTCYAN;
 		var first_collection = null;
 		directory(dir + '/*.bin').forEach(
-			function (e, i) {
+			function (e) {
 				if (e.search(EXCLUDE_FILES) > -1) return;
 				const sauce = sauce_lib.read(e);
 				if (!sauce) return;
@@ -452,20 +481,20 @@ function CollectionLister(dir, parent_frame) {
 				state.collection = null;
 			}
 		} else {
-			if (cmd.toLowerCase() == 'q') {
+			if (cmd.key.toLowerCase() == 'q') {
 				return false;
-			} else if (cmd == KEY_LEFT) {
+			} else if (cmd.key == KEY_LEFT) {
 				var num_avatars = Math.floor(state.tree.currentItem.sauce.filesize / avatar_lib.size);
 				state.preview = state.preview - 1;
 				if (state.preview < 0) state.preview = num_avatars - 1;
 				display_preview(state.tree.currentItem.file, state.preview);
-			} else if (cmd == KEY_RIGHT) {
+			} else if (cmd.key == KEY_RIGHT) {
 				var num_avatars = Math.floor(state.tree.currentItem.sauce.filesize / avatar_lib.size);
 				state.preview = (state.preview + 1) % num_avatars;
 				display_preview(state.tree.currentItem.file, state.preview);
 			} else if (
-				(state.tree.index > 0 || cmd != KEY_UP) &&
-				(state.tree.index < state.tree.items.length - 1 || cmd != KEY_DOWN) &&
+				(state.tree.index > 0 || cmd.key != KEY_UP) &&
+				(state.tree.index < state.tree.items.length - 1 || cmd.key != KEY_DOWN) &&
 				state.tree.getcmd(cmd)
 			) {
 				frames.info.clear();
@@ -565,7 +594,7 @@ function AvatarEditor(parent_frame, on_exit) {
 	}
 
 	this.getcmd = function (cmd) {
-		editor.getcmd(cmd);
+		editor.getcmd(cmd.key);
 	}
 
 	this.cycle = function () {
@@ -589,22 +618,22 @@ function MainMenu(parent_frame) {
 	const user_fname = avatar_lib.localuser_fname(user.number);
 
 	const frames = {
-		parent : parent_frame,
-		container : null,
-		tree : null,
-		info : null,
-		user_avatar : null
+		parent: parent_frame,
+		container: null,
+		tree: null,
+		info: null,
+		user_avatar: null
 	};
 
 	const state = {
-		ae : null,
-		cl : null,
-		tree : null,
-        ed_item : null,
-		timer : new Timer(),
-		utime : file_exists(user_fname) ? file_date(user_fname) : -1,
-        user_avatar : null,
-        opt_out_item : null
+		ae: null,
+		cl: null,
+		tree: null,
+        ed_item: null,
+		timer: new Timer(),
+		utime: file_exists(user_fname) ? file_date(user_fname) : -1,
+        user_avatar: null,
+        opt_out_item: null
 	};
 
 	function load_user_avatar() {
@@ -618,11 +647,9 @@ function MainMenu(parent_frame) {
 				'My Avatar', WHITE
 			);
             state.user_avatar = {};
-            Object.keys(user_avatar).forEach(
-                function (e) {
-                    if (e !== 'data') state.user_avatar[e] = user_avatar[e];
-                }
-            );
+            Object.keys(user_avatar).forEach(function (e) {
+				if (e !== 'data') state.user_avatar[e] = user_avatar[e];
+			});
             if (state.user_avatar.disabled) {
                 for (var y = 1; y < frames.user_avatar.data.length - 2; y++) {
                     if (!Array.isArray(frames.user_avatar.data[y])) continue;
@@ -710,51 +737,40 @@ function MainMenu(parent_frame) {
 		state.tree.colors.lfg = WHITE;
 		state.tree.colors.lbg = BG_BLUE;
 		state.tree.colors.kfg = LIGHTCYAN;
-		state.tree.addItem(
-			'Select an avatar', function () {
-				state.tree.close();
-				state.cl = new CollectionLister(avatar_lib.local_library(), frames.parent);
-				state.cl.open();
-			}
-		);
-		state.tree.addItem(
-			'Upload an avatar', function () {
-				console.clear(WHITE);
-				console.putmsg('Your avatar must be 10 x 6 characters in size and saved in binary format.\r\n');
-				if (upload_avatar()) {
-					console.putmsg('Your avatar has been updated.');
-				} else {
-					console.putmsg('An error was encountered.  Your avatar has nto been updated.');
-				}
-				console.clear(LIGHTGRAY);
-				frames.parent.invalidate();
-			}
-		);
-		state.tree.addItem(
-			'Download your avatar', function () {
-				console.clear(WHITE);
-				console.putmsg(
-					'Avatars are ' +
-					avatar_lib.defs.width + ' x ' + avatar_lib.defs.height +
-					' characters in size, and are sent in binary format.\r\n'
-				);
-				download_avatar();
-				console.clear(LIGHTGRAY);
-				frames.parent.invalidate();
-			}
-		);
-		state.tree.addItem(
-			'Edit your avatar', function () {
-				state.ae = new AvatarEditor(
-					frames.parent,
-					function () {
-						state.ae.close();
-						state.ae = null;
-					}
-				);
-				state.ae.open();
+		state.tree.addItem('Select an avatar', function () {
+			state.tree.close();
+			state.cl = new CollectionLister(avatar_lib.local_library(), frames.parent);
+			state.cl.open();
+		});
+		state.tree.addItem('Upload an avatar', function () {
+			console.clear(WHITE);
+			console.putmsg('Your avatar must be 10 x 6 characters in size and saved in binary format.\r\n');
+			if (upload_avatar()) {
+				console.putmsg('Your avatar has been updated.');
+			} else {
+				console.putmsg('An error was encountered.  Your avatar has nto been updated.');
 			}
-		);
+			console.clear(LIGHTGRAY);
+			frames.parent.invalidate();
+		});
+		state.tree.addItem('Download your avatar', function () {
+			console.clear(WHITE);
+			console.putmsg(
+				'Avatars are ' +
+				avatar_lib.defs.width + ' x ' + avatar_lib.defs.height +
+				' characters in size, and are sent in binary format.\r\n'
+			);
+			download_avatar();
+			console.clear(LIGHTGRAY);
+			frames.parent.invalidate();
+		});
+		state.tree.addItem('Edit your avatar', function () {
+			state.ae = new AvatarEditor(frames.parent, function () {
+				state.ae.close();
+				state.ae = null;
+			});
+			state.ae.open();
+		});
         state.ed_item = state.tree.addItem(
             tree_strings[state.user_avatar !== null && state.user_avatar.disabled ? 'enable' : 'disable'],
             enable_disable
@@ -762,14 +778,12 @@ function MainMenu(parent_frame) {
         if (state.user_avatar === null) {
             state.ed_item.disable();
             state.ed_item.hide();
-            state.opt_out_item = state.tree.addItem(
-                "I don't want an avatar", function () {
-                    avatar_lib.update_localuser(user.number, '');
-                    avatar_lib.enable_localuser(user.number, false);
-                    state.opt_out_item.hide();
-                    state.tree.getcmd(KEY_UP);
-                }
-            );
+            state.opt_out_item = state.tree.addItem("I don't want an avatar", function () {
+				avatar_lib.update_localuser(user.number, '');
+				avatar_lib.enable_localuser(user.number, false);
+				state.opt_out_item.hide();
+				state.tree.getcmd(KEY_UP);
+			});
         }
 		state.tree.open();
 
@@ -792,7 +806,7 @@ function MainMenu(parent_frame) {
                     state.opt_out_item.hide();
                 }
 			}
-		} else if (cmd.toLowerCase() == 'q') {
+		} else if (cmd.key.toLowerCase() == 'q') {
 			return false;
 		} else {
 			state.tree.getcmd(cmd);
@@ -821,18 +835,21 @@ function MainMenu(parent_frame) {
 var sys_status, console_attr;
 
 function init() {
-	sys_status = bbs.sys_status;
-	console_attr = console.attributes;
 	bbs.sys_status|=SS_MOFF;
 	console.clear(LIGHTGRAY);
 	ansiterm.send("ext_mode", "clear", "cursor");
     js.on_exit("console.ctrlkey_passthru = " + console.ctrlkey_passthru);
 	js.on_exit("ansiterm.send('ext_mode', 'set', 'cursor')");
+	js.on_exit("mouse_enable(false);");
+	js.on_exit("bbs.sys_status = " + bbs.sys_status + ";");
+	js.on_exit("console.attributes = " + console.attributes + ";");
+	js.on_exit("console.clear();");
 	console.ctrlkey_passthru|=(1<<11);      // Disable Ctrl-K handling in sbbs
 	console.ctrlkey_passthru|=(1<<16);      // Disable Ctrl-P handling in sbbs
 	console.ctrlkey_passthru|=(1<<20);      // Disable Ctrl-T handling in sbbs
 	console.ctrlkey_passthru|=(1<<21);      // Disable Ctrl-U handling in sbbs
 	console.ctrlkey_passthru|=(1<<26);      // Disable Ctrl-Z handling in sbbs
+	mouse_enable(true);
 }
 
 function main() {
@@ -848,8 +865,8 @@ function main() {
 	const menu = new MainMenu(frame);
 	menu.open();
 	while (true) {
-		var i = console.inkey(K_NONE);
-		if (i !== '' && !menu.getcmd(i)) break;
+		var i = mouse_getkey(K_NONE, 5, true); //console.inkey(K_NONE);
+		if (!menu.getcmd(i)) break;
 		menu.cycle();
 		if (frame.cycle()) bury_cursor();
 	}
@@ -858,12 +875,5 @@ function main() {
 
 }
 
-function clean_up() {
-	bbs.sys_status = sys_status;
-	console.attributes = console_attr;
-	console.clear();
-}
-
 init();
 main();
-clean_up();
-- 
GitLab