Differentiate between script and real "selchange" events in custom dialogs

I'm trying to have an "undo selection" button for a multi-select listview
So on every selchange event I'm saving the current selection in some global vector
On button click I restore lv.value = old_sel of this listview to some previously saved state.
But I want these "artificial" selection changes to be ignored and not saved. I've tried setting a global nosave variable before setting the value and after it, but it seems to have no effect as, I guess, this artificial selection happens asynchronously

So how can I differentiate between these two types of selchange events?

Using a variable should work to know when the script is reacting to events it has triggered itself.

So you're saying that sel_save within a hotkey event should be set to true only AFTER all selchange events from .value= are processed? Because all the selchange events print sel_save as true all the time even for these events

sel_save = false; // prevent this event from being recorded
dbg("undid selection, set sel_save to false");
lv.value=sel_ids;
dbg("reset sel_save to true");
sel_save = true; // prevent this event from being recorded

(will try to prepare a simplified example later)

In this example I never get a red error print activated if sel_save is false even though I set it to false before manually changing selection

Test.dcf (4.7 KB)

I see what you mean. Not what I expected either. Maybe we can improve things, with a way to suppress the notifications or something.

For now, you can work around the problem using a timer:

var lv_name = '‹tab✗';

function guitest(icon)
{
	var Dlg = DOpus.Dlg; Dlg.template = "✗Tabs";
	var DC=DOpus.Create;
	Dlg.Create(); // create detached
	var lv=Dlg.Control(lv_name);

	var j = 5; while (j--) {
		var i = lv.AddItem("a"+j);
		lv.GetItemAt(i).subitems(0) = "lbl"+j;
		lv.GetItemAt(i).subitems(1) = "path"+j;
	}

	var sel_save = true;
	while (true) {
	    var Msg = Dlg.GetMsg();
	    if (!Msg.result) break;

	    if (Msg.event === "selchange") {
			if (sel_save) {
				dbgv("selchange true");
			} else {
				err("selchange false");
			}
		}

		if (Msg.event === "click") {
			if (Msg.Control === "btnU") {
				p("Undo start");
				sel_save = false;
				var lv=Dlg.Control(lv_name);
				lv.value = DC.Vector(0,2); // select 1st and 3rd items
				Dlg.SetTimer(1,"sel_save");
				p("Undo end");
			}
		}

		if (Msg.event === "timer") {
			if (Msg.Control ==="sel_save") {
				Dlg.KillTimer("sel_save");
				sel_save = true;
				dbgv("Timer");
			}
		}
	}
	retVal = Dlg.result;
}

function OnClick(cmdD) {
 var aaa = guitest();
}

function T(t) {return DOpus.TypeOf(t)}
function p(text) {DOpus.Output(text     );}
function dbg(text) {DOpus.Output(text     );}
function dbgv(text) {DOpus.Output(text     );}
function err(text) {DOpus.Output(text,true     );}

Thanks, have considered timers, but haven't tested them whether they'd differentiate between a key hold/multiselects and artificial send yet

When you improve this, please also add a way to "group" one batch of events together as otherwise I don't know how to do undo properly since the number of events can differ depending on the type of user action, so I don't know by how many events to go back to to restore a single action

I'm not sure we can group the events in any meaningful way. They come from the operating system as individual events, and we just forward them to the script.

I see, are you aware of any apps caring enough about user selection to preserve it :slight_smile: (hate it when you carefuly multi-select something and then 1 wrong click ruins everything)?

What do they do?

I guess one option would be to carefully track key/mouse events to divine start/end of 1 user action, but then scripts don't have access to those, only its hotkeys

You could use another timer, started in the selchange events, so you only save the state once when the timer fires, after things settle down.

Maybe will try that or just do undos by 1 (de)sel event, after all, you could just hold the undo button to make it go faster

1 Like