From 93ca78b1bd20f77413896b6c19dc24a8c62742af Mon Sep 17 00:00:00 2001 From: Kenneth VanderLinde Date: Thu, 2 Nov 2023 01:08:30 -0700 Subject: [PATCH] Propagate frame rate cap changes to each ZoneRenderer The `DebounceExecutor` is now able to modify its delay so that existing maps can receive updates to the frame rate cap. --- .../rptools/maptool/client/DebounceExecutor.java | 16 +++++++++++----- .../ui/preferencesdialog/PreferencesDialog.java | 4 ++++ .../maptool/client/ui/zone/ZoneRenderer.java | 8 +++++--- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/rptools/maptool/client/DebounceExecutor.java b/src/main/java/net/rptools/maptool/client/DebounceExecutor.java index e432f23438..31e10170ba 100644 --- a/src/main/java/net/rptools/maptool/client/DebounceExecutor.java +++ b/src/main/java/net/rptools/maptool/client/DebounceExecutor.java @@ -50,7 +50,7 @@ public class DebounceExecutor { Executors.newSingleThreadScheduledExecutor(threadFactory); /** The time, in milliseconds, during which to throttle subsequent requests to run the task. */ - private final long delay; + private final AtomicLong delay; /** A {@link Runnable} representing the task to be managed. */ private final Runnable task; @@ -71,14 +71,20 @@ public class DebounceExecutor { * @param task The task to be executed after the delay elapses. */ public DebounceExecutor(long delay, @Nonnull Runnable task) { - this.delay = delay; + this.delay = new AtomicLong(delay); this.task = task; } + public void setDelay(long delay) { + this.delay.set(delay); + } + /** Dispatches a task to be executed by this {@link DebounceExecutor} instance. */ public void dispatch() { - if (this.delay < 1) { - this.task.run(); + final var delay = this.delay.get(); + if (delay < 1) { + // Have to run via the executor otherwise it's possible the task runs in parallel with itself. + this.executor.schedule(this.task, 0, TimeUnit.MILLISECONDS); return; } @@ -93,7 +99,7 @@ public void dispatch() { final var now = System.currentTimeMillis(); if (now >= taskScheduledTime) { // This request is not redundant, so we need to schedule it. - final var nextTargetTime = Math.max(now, taskScheduledTime + this.delay); + final var nextTargetTime = Math.max(now, taskScheduledTime + delay); // If this check fails, that means someone beat us to the punch and our task is now redundant. if (this.taskScheduledTime.compareAndSet(taskScheduledTime, nextTargetTime)) { this.executor.schedule(this.task, nextTargetTime - now, TimeUnit.MILLISECONDS); diff --git a/src/main/java/net/rptools/maptool/client/ui/preferencesdialog/PreferencesDialog.java b/src/main/java/net/rptools/maptool/client/ui/preferencesdialog/PreferencesDialog.java index f30e655e91..6afd3a7fc2 100644 --- a/src/main/java/net/rptools/maptool/client/ui/preferencesdialog/PreferencesDialog.java +++ b/src/main/java/net/rptools/maptool/client/ui/preferencesdialog/PreferencesDialog.java @@ -602,6 +602,10 @@ public void focusLost(FocusEvent e) { @Override protected void storeNumericValue(Integer value) { AppPreferences.setFrameRateCap(value); + + for (final var renderer : MapTool.getFrame().getZoneRenderers()) { + renderer.setFrameRateCap(value); + } } @Override diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/ZoneRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/ZoneRenderer.java index 59e5706f02..1fb99f24ca 100644 --- a/src/main/java/net/rptools/maptool/client/ui/zone/ZoneRenderer.java +++ b/src/main/java/net/rptools/maptool/client/ui/zone/ZoneRenderer.java @@ -176,9 +176,7 @@ public ZoneRenderer(Zone zone) { } this.zone = zone; - // The interval, in milliseconds, during which calls to repaint() will be debounced. - int repaintDebounceInterval = 1000 / AppPreferences.getFrameRateCap(); - repaintDebouncer = new DebounceExecutor(repaintDebounceInterval, this::repaint); + repaintDebouncer = new DebounceExecutor(1000 / AppPreferences.getFrameRateCap(), this::repaint); setFocusable(true); setZoneScale(new Scale()); @@ -223,6 +221,10 @@ public void mouseMoved(MouseEvent e) { new MapToolEventBus().getMainEventBus().register(this); } + public void setFrameRateCap(int cap) { + this.repaintDebouncer.setDelay(1000 / cap); + } + public void setAutoResizeStamp(boolean value) { this.autoResizeStamp = value; }