Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ## Clients get extended with this module, because apparently I can't change
- ## the Subtlext::Client class
- module ClientWrapper
- def self.make_setter *args
- args.each do |arg|
- class_eval("def #{arg} x
- self.#{arg} = x
- end")
- end
- end
- def self.make_toggle_setter *args
- args.each do |arg|
- class_eval("def #{arg} x
- toggle_#{arg} if x != is_#{arg}?
- end")
- end
- end
- ## Subtle provides things like `c.gravity = :foo` but that won't work if
- ## the client is instance_eval'd into a block, so this provides versions
- ## that do the assignment so you can say things like `gravity :foo`
- make_setter :flags, :geometry, :gravity, :tags
- ## Subtle only provides things like `is_float?` and `toggle_float`, so this
- ## creates some nice wrappers so you can say things like `c.float true`
- ## rather than `c.toggle_float unless c.is_float?`
- make_toggle_setter :borderless, :fixed, :float, :full,
- :resize, :stick, :urgent, :zaphod
- ## Needed so assigning the gravity sets it on all the client's views rather
- ## than only the current one
- def gravity= x
- if Symbol === x
- views.each { |v| super v => x }
- else
- super
- end
- end
- ## Returns true if the client would be matched by the argument `x`
- ##
- ## It uses the same matching rules as `match foo` inside a tag, with the
- ## sole exception that strings are exact matches rather than treated as
- ## regexps
- def matches? x
- case x
- when String
- x == instance or x == klass
- when Regexp
- x.match(instance) or x.match(klass)
- when Hash
- x.all? do |k, v|
- k = (k == :class) ? klass
- : send(k)
- (String === v) ? v == k
- : v.match(k)
- end
- else
- raise TypeError
- end
- end
- end
- # TODO: better way to access the old stuff...
- $self = self
- alias old_view view
- alias old_tag tag
- class Tag
- def initialize name, &f
- @clients = []
- @on_match = []
- ## Special DSL sugar that lets you pass in a block with no arguments
- if block_given?
- if f.arity == 0
- instance_eval &f
- else
- f.call self
- end
- end
- ## Needed because `$self.old_tag` evaluates the block's body in a
- ## different environment
- _clients = @clients
- _gravity = @gravity
- _on_match = @on_match
- $self.old_tag name do
- _clients.each { |x| match x }
- gravity _gravity if _gravity
- on_match do |c|
- ## Makes the methods in `ClientWrapper` available to the client
- # TODO: potentially slow, maybe I can cache it somehow?
- c.extend ClientWrapper
- _on_match.each { |x| x.call c }
- end
- end
- end
- def on x, &f
- if x == :match
- ## DSL sugar
- @on_match << (f.arity == 0 ? lambda { |c| c.instance_eval &f } : f)
- else
- raise NoMethodError
- end
- end
- ## Sets the gravity of either the entire view, or an individual client
- ## within the view
- def gravity g, x=nil
- if x
- @clients << x
- @on_match << lambda { |c| c.gravity = g if c.matches? x }
- else
- @gravity = g
- end
- end
- ## Matches a client and optionally calls a block, passing it the client
- def client x, &f
- @clients << x
- if block_given?
- ## DSL sugar
- @on_match << (f.arity == 0 ? lambda { |c| c.instance_eval &f if c.matches? x }
- : lambda { |c| yield c if c.matches? x })
- end
- end
- end
- class View < Tag
- def initialize name, &f
- @icon = []
- @tag = [name]
- ## Calls the Tag class's initialize
- super
- ## This is needed because views can't have more than one
- ## `match` method, so we have to union them together into
- ## a single `match`
- _tag = Regexp.union @tag
- _icon = @icon
- _dynamic = @dynamic
- _icon_only = @icon_only
- $self.old_view name do
- match _tag
- _icon.each { |x| icon x }
- dynamic true if _dynamic
- icon_only true if _icon_only
- end
- end
- def icon x
- @icon << x
- end
- def tag x
- @tag << x
- end
- def dynamic x
- @dynamic = x
- end
- def icon_only x
- @icon_only = x
- end
- end
- ## These two are just to make it a bit shorter and cleaner looking
- def view name, &f
- View.new(name, &f)
- end
- def tag name, &f
- Tag.new(name, &f)
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement