lib/glimmer/swt/custom/animation.rb in glimmer-dsl-swt-4.18.4.4 vs lib/glimmer/swt/custom/animation.rb in glimmer-dsl-swt-4.18.4.5
- old
+ new
@@ -1,243 +1,247 @@
-# Copyright (c) 2007-2021 Andy Maleh
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-require 'glimmer/swt/properties'
-
-module Glimmer
- module SWT
- module Custom
- # Represents an animation declaratively
- class Animation
- include Properties # TODO rename to Properties
-
- class << self
- def schedule_frame_animation(animation, &frame_animation_block)
- frame_animation_queue(animation).prepend(frame_animation_block)
- swt_display.async_exec do
- frame_animation_queue(next_animation)&.pop&.call
- end
- end
-
- def next_animation
- animation = nil
- while frame_animation_queues.values.reduce(:+)&.any? && (animation.nil? || frame_animation_queue(animation).last.nil?)
- animation = frame_animation_queues.keys[next_animation_index]
- frame_animation_queues.delete(animation) if frame_animation_queues.values.reduce(:+)&.any? && !animation.nil? && frame_animation_queue(animation).empty?
- end
- animation
- end
-
- def next_animation_index
- next_schedule_index % frame_animation_queues.keys.size
- end
-
- def next_schedule_index
- unless defined? @@next_schedule_index
- @@next_schedule_index = 0
- else
- @@next_schedule_index += 1
- end
- end
-
- def frame_animation_queues
- unless defined? @@frame_animation_queues
- @@frame_animation_queues = {}
- end
- @@frame_animation_queues
- end
-
- def frame_animation_queue(animation)
- frame_animation_queues[animation] ||= []
- end
-
- def swt_display
- unless defined? @@swt_display
- @@swt_display = DisplayProxy.instance.swt_display
- end
- @@swt_display
- end
- end
-
- attr_reader :parent, :options, :frame_index, :cycle
- alias current_frame_index frame_index
- attr_accessor :frame_block, :every, :cycle_count, :frame_count, :started, :duration_limit
- alias started? started
- # TODO consider supporting an async: false option
-
- def initialize(parent)
- @parent = parent
- @started = true
- @frame_index = 0
- @cycle_count_index = 0
- @start_number = 0 # denotes the number of starts (increments on every start)
- self.class.swt_display # ensures initializing variable to set from GUI thread
- end
-
- def post_add_content
- @parent.on_widget_disposed { stop }
- start if started?
- end
-
- # Starts an animation that is indefinite or has never been started before (i.e. having `started: false` option).
- # Otherwise, resumes a stopped animation that has not been completed.
- def start
- return if @start_number > 0 && started?
- @start_number += 1
- @started = true
- @start_time = Time.now
- @original_start_time = @start_time if @duration.nil?
- # TODO track when finished in a variable for finite animations (whether by frame count, cycle count, or duration limit)
- Thread.new do
- start_number = @start_number
- if cycle_count.is_a?(Integer) && cycle.is_a?(Array)
- (cycle_count * cycle.length).times do
- break unless draw_frame(start_number)
- end
- else
- loop do
- # this code has to be duplicated to break from a loop (break keyword only works when literally in a loop block)
- break unless draw_frame(start_number)
- end
- end
- end
- end
-
- def stop
- return if stopped?
- @started = false
- @duration = (Time.now - @start_time) + @duration.to_f if duration_limited? && !@start_time.nil?
- end
-
- # Restarts an animation (whether indefinite or not and whether stopped or not)
- def restart
- @original_start_time = @start_time = nil
- @duration = nil
- @frame_index = 0
- @cycle_count_index = 0
- stop
- start
- end
-
- def stopped?
- !started?
- end
-
- def finite?
- frame_count_limited? || cycle_limited? || duration_limited?
- end
-
- def infinite?
- !finite?
- end
- alias indefinite? infinite?
-
- def has_attribute?(attribute_name, *args)
- respond_to?(ruby_attribute_setter(attribute_name)) && respond_to?(ruby_attribute_getter(attribute_name))
- end
-
- def set_attribute(attribute_name, *args)
- send(ruby_attribute_setter(attribute_name), *args)
- end
-
- def get_attribute(attribute_name)
- send(ruby_attribute_getter(attribute_name))
- end
-
- def cycle=(*args)
- if args.size == 1
- if args.first.is_a?(Array)
- @cycle = args.first
- else
- @cycle = [args.first]
- end
- elsif args.size > 1
- @cycle = args
- end
- end
-
- def cycle_enabled?
- @cycle.is_a?(Array)
- end
-
- def cycle_limited?
- cycle_enabled? && @cycle_count.is_a?(Integer)
- end
-
- def duration_limited?
- @duration_limit.is_a?(Integer)
- end
-
- def frame_count_limited?
- @frame_count.is_a?(Integer)
- end
-
- def surpassed_duration_limit?
- duration_limited? && ((Time.now - @start_time) > (@duration_limit - @duration.to_f))
- end
-
- def within_duration_limit?
- !surpassed_duration_limit?
- end
-
- private
-
- # Returns true on success of painting a frame and false otherwise
- def draw_frame(start_number)
- return false if stopped? ||
- start_number != @start_number ||
- (frame_count_limited? && @frame_index == @frame_count) ||
- (cycle_limited? && @cycle_count_index == @cycle_count) ||
- surpassed_duration_limit?
- block_args = [@frame_index]
- block_args << @cycle[@frame_index % @cycle.length] if cycle_enabled?
- current_frame_index = @frame_index
- current_cycle_count_index = @cycle_count_index
- self.class.schedule_frame_animation(self) do
- if started? && start_number == @start_number && within_duration_limit?
- @parent.clear_shapes
- @parent.content {
- frame_block.call(*block_args)
- }
- @parent.redraw
- else
- if stopped? && @frame_index > current_frame_index
- @started = false
- @frame_index = current_frame_index
- @cycle_count_index = current_cycle_count_index
- end
- end
- end
- @frame_index += 1
- @cycle_count_index += 1 if cycle_limited? && (@frame_index % @cycle&.length&.to_i) == 0
- sleep(every) if every.is_a?(Numeric)
- true
- rescue => e
- Glimmer::Config.logger.error {e}
- false
- end
-
- end
-
- end
-
- end
-
-end
+# Copyright (c) 2007-2021 Andy Maleh
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+require 'glimmer/swt/properties'
+
+module Glimmer
+ module SWT
+ module Custom
+ # Represents an animation declaratively
+ class Animation
+ include Properties
+
+ class << self
+ def schedule_frame_animation(animation, &frame_animation_block)
+ frame_animation_queue(animation).prepend(frame_animation_block)
+ swt_display.async_exec do
+ frame_animation_queue(next_animation)&.pop&.call
+ end
+ end
+
+ def next_animation
+ animation = nil
+ while frame_animation_queues.values.reduce(:+)&.any? && (animation.nil? || frame_animation_queue(animation).last.nil?)
+ animation = frame_animation_queues.keys[next_animation_index]
+ frame_animation_queues.delete(animation) if frame_animation_queues.values.reduce(:+)&.any? && !animation.nil? && frame_animation_queue(animation).empty?
+ end
+ animation
+ end
+
+ def next_animation_index
+ next_schedule_index % frame_animation_queues.keys.size
+ end
+
+ def next_schedule_index
+ unless defined? @@next_schedule_index
+ @@next_schedule_index = 0
+ else
+ @@next_schedule_index += 1
+ end
+ end
+
+ def frame_animation_queues
+ unless defined? @@frame_animation_queues
+ @@frame_animation_queues = {}
+ end
+ @@frame_animation_queues
+ end
+
+ def frame_animation_queue(animation)
+ frame_animation_queues[animation] ||= []
+ end
+
+ def swt_display
+ unless defined? @@swt_display
+ @@swt_display = DisplayProxy.instance.swt_display
+ end
+ @@swt_display
+ end
+ end
+
+ attr_reader :parent, :options, :frame_index, :cycle
+ alias current_frame_index frame_index
+ attr_accessor :frame_block, :every, :cycle_count, :frame_count, :started, :duration_limit
+ alias started? started
+ # TODO consider supporting an async: false option
+
+ def initialize(parent)
+ @parent = parent
+ @started = true
+ @frame_index = 0
+ @cycle_count_index = 0
+ @start_number = 0 # denotes the number of starts (increments on every start)
+ self.class.swt_display # ensures initializing variable to set from GUI thread
+ end
+
+ def post_add_content
+ if @dispose_listener_registration.nil?
+ @dispose_listener_registration = @parent.on_widget_disposed { stop }
+ start if started?
+ end
+ end
+
+ # Starts an animation that is indefinite or has never been started before (i.e. having `started: false` option).
+ # Otherwise, resumes a stopped animation that has not been completed.
+ def start
+ return if @start_number > 0 && started?
+ @start_number += 1
+ @started = true
+ @start_time = Time.now
+ @original_start_time = @start_time if @duration.nil?
+ # TODO track when finished in a variable for finite animations (whether by frame count, cycle count, or duration limit)
+ Thread.new do
+ start_number = @start_number
+ if cycle_count.is_a?(Integer) && cycle.is_a?(Array)
+ (cycle_count * cycle.length).times do
+ break unless draw_frame(start_number)
+ end
+ else
+ loop do
+ # this code has to be duplicated to break from a loop (break keyword only works when literally in a loop block)
+ break unless draw_frame(start_number)
+ end
+ end
+ end
+ end
+
+ def stop
+ return if stopped?
+ @started = false
+ @duration = (Time.now - @start_time) + @duration.to_f if duration_limited? && !@start_time.nil?
+ end
+
+ # Restarts an animation (whether indefinite or not and whether stopped or not)
+ def restart
+ @original_start_time = @start_time = nil
+ @duration = nil
+ @frame_index = 0
+ @cycle_count_index = 0
+ stop
+ start
+ end
+
+ def stopped?
+ !started?
+ end
+
+ def finite?
+ frame_count_limited? || cycle_limited? || duration_limited?
+ end
+
+ def infinite?
+ !finite?
+ end
+ alias indefinite? infinite?
+
+ def has_attribute?(attribute_name, *args)
+ respond_to?(ruby_attribute_setter(attribute_name)) && respond_to?(ruby_attribute_getter(attribute_name))
+ end
+
+ def set_attribute(attribute_name, *args)
+ send(ruby_attribute_setter(attribute_name), *args)
+ end
+
+ def get_attribute(attribute_name)
+ send(ruby_attribute_getter(attribute_name))
+ end
+
+ def cycle=(*args)
+ if args.size == 1
+ if args.first.is_a?(Array)
+ @cycle = args.first
+ else
+ @cycle = [args.first]
+ end
+ elsif args.size > 1
+ @cycle = args
+ end
+ end
+
+ def cycle_enabled?
+ @cycle.is_a?(Array)
+ end
+
+ def cycle_limited?
+ cycle_enabled? && @cycle_count.is_a?(Integer)
+ end
+
+ def duration_limited?
+ @duration_limit.is_a?(Integer)
+ end
+
+ def frame_count_limited?
+ @frame_count.is_a?(Integer)
+ end
+
+ def surpassed_duration_limit?
+ duration_limited? && ((Time.now - @start_time) > (@duration_limit - @duration.to_f))
+ end
+
+ def within_duration_limit?
+ !surpassed_duration_limit?
+ end
+
+ private
+
+ # Returns true on success of painting a frame and false otherwise
+ def draw_frame(start_number)
+ return false if stopped? ||
+ start_number != @start_number ||
+ (frame_count_limited? && @frame_index == @frame_count) ||
+ (cycle_limited? && @cycle_count_index == @cycle_count) ||
+ surpassed_duration_limit?
+ block_args = [@frame_index]
+ block_args << @cycle[@frame_index % @cycle.length] if cycle_enabled?
+ current_frame_index = @frame_index
+ current_cycle_count_index = @cycle_count_index
+ self.class.schedule_frame_animation(self) do
+ if started? && start_number == @start_number && within_duration_limit?
+ unless @parent.isDisposed
+ @parent.clear_shapes
+ @parent.content {
+ frame_block.call(*block_args)
+ }
+ @parent.redraw
+ end
+ else
+ if stopped? && @frame_index > current_frame_index
+ @started = false
+ @frame_index = current_frame_index
+ @cycle_count_index = current_cycle_count_index
+ end
+ end
+ end
+ @frame_index += 1
+ @cycle_count_index += 1 if cycle_limited? && (@frame_index % @cycle&.length&.to_i) == 0
+ sleep(every) if every.is_a?(Numeric)
+ true
+ rescue => e
+ Glimmer::Config.logger.error {e}
+ false
+ end
+
+ end
+
+ end
+
+ end
+
+end