royw-shoeshine 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.rdoc +31 -0
- data/Rakefile +48 -0
- data/VERSION.yml +4 -0
- data/examples/action.rb +36 -0
- data/examples/command_widget.rb +26 -0
- data/examples/dd_menu_action.rb +22 -0
- data/examples/dd_menu_widget.rb +51 -0
- data/examples/example_app.rb +58 -0
- data/examples/index_action.rb +22 -0
- data/examples/index_widget.rb +23 -0
- data/examples/nav.rb +9 -0
- data/examples/ordered_list_action.rb +22 -0
- data/examples/ordered_list_widget.rb +11 -0
- data/examples/page_widget.rb +11 -0
- data/examples/title_widget.rb +12 -0
- data/examples/unordered_list_action.rb +22 -0
- data/examples/unordered_list_widget.rb +48 -0
- data/lib/shoeshine/drop_down_menu.rb +94 -0
- data/lib/shoeshine/horizontal_rule.rb +17 -0
- data/lib/shoeshine/list.rb +19 -0
- data/lib/shoeshine/list_item.rb +65 -0
- data/lib/shoeshine/unordered_list.rb +32 -0
- data/lib/shoeshine/widget.rb +5 -0
- data/lib/shoeshine.rb +15 -0
- data/spec/drop_down_menu_spec.rb +72 -0
- data/spec/spec_helper.rb +9 -0
- metadata +95 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Roy Wright
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
= shoeshine
|
2
|
+
|
3
|
+
This is a collection of UI elements for shoes (http://shoooes.net).
|
4
|
+
|
5
|
+
The collection currently includes:
|
6
|
+
|
7
|
+
* UnorderedList is an unordered lists with various bullets
|
8
|
+
* ListItems is a handy wrapper for placing things in the list
|
9
|
+
* DropDownMenu is an inplace drop down menu that can serve as popup menus
|
10
|
+
* An example application to show them off with
|
11
|
+
|
12
|
+
TODOs include:
|
13
|
+
* ordered lists
|
14
|
+
* horizontal lists
|
15
|
+
* toolbar (horizontal list of icons)
|
16
|
+
* maybe a menubar
|
17
|
+
|
18
|
+
Usage
|
19
|
+
|
20
|
+
# examples/example.app.rb
|
21
|
+
|
22
|
+
A Big THANK YOU to Matt Payne for slimtimeronshoes which pointed
|
23
|
+
me in the right direction for structuring shoes applications.
|
24
|
+
|
25
|
+
|
26
|
+
Enjoy,
|
27
|
+
Roy
|
28
|
+
|
29
|
+
== Copyright
|
30
|
+
|
31
|
+
Copyright (c) 2009 Roy Wright. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "shoeshine"
|
8
|
+
gem.summary = %Q{TODO}
|
9
|
+
gem.email = "roy@wright.org"
|
10
|
+
gem.homepage = "http://github.com/royw/shoeshine"
|
11
|
+
gem.authors = ["Roy Wright"]
|
12
|
+
|
13
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
14
|
+
end
|
15
|
+
rescue LoadError
|
16
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'spec/rake/spectask'
|
20
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
21
|
+
spec.libs << 'lib' << 'spec'
|
22
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
23
|
+
end
|
24
|
+
|
25
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
26
|
+
spec.libs << 'lib' << 'spec'
|
27
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
28
|
+
spec.rcov = true
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
task :default => :spec
|
33
|
+
|
34
|
+
require 'rake/rdoctask'
|
35
|
+
Rake::RDocTask.new do |rdoc|
|
36
|
+
if File.exist?('VERSION.yml')
|
37
|
+
config = YAML.load(File.read('VERSION.yml'))
|
38
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
39
|
+
else
|
40
|
+
version = ""
|
41
|
+
end
|
42
|
+
|
43
|
+
rdoc.rdoc_dir = 'rdoc'
|
44
|
+
rdoc.title = "shoeshine #{version}"
|
45
|
+
rdoc.rdoc_files.include('README*')
|
46
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
47
|
+
end
|
48
|
+
|
data/VERSION.yml
ADDED
data/examples/action.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# From Matt Payne's slimtimeronshoes
|
2
|
+
|
3
|
+
require 'nav'
|
4
|
+
require 'title_widget'
|
5
|
+
require 'page_widget'
|
6
|
+
require 'command_widget'
|
7
|
+
|
8
|
+
class Action
|
9
|
+
include Nav
|
10
|
+
|
11
|
+
attr_accessor :app
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@command_widget = CommandWidget.new
|
15
|
+
@title_widget = TitleWidget.new
|
16
|
+
@page_widget = PageWidget.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def execute(obj=nil)
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
def page_layout(&blk)
|
24
|
+
@page_widget.app = app
|
25
|
+
@page_widget.show
|
26
|
+
|
27
|
+
app.flow(:width => '100%') do
|
28
|
+
@title_widget.app = app
|
29
|
+
@title_widget.show
|
30
|
+
@command_widget.app = app
|
31
|
+
@command_widget.show(:width => COMMAND_AREA_WIDTH)
|
32
|
+
blk.call unless blk.nil?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class CommandWidget
|
2
|
+
include Widget
|
3
|
+
include Nav
|
4
|
+
|
5
|
+
def show(opt={})
|
6
|
+
app.stack(opt) do
|
7
|
+
app.background app.gradient(app.rgb(0, 255, 255), app.rgb(255, 0, 255), :angle => -35)
|
8
|
+
command_list = UnorderedList.new(app, :left_margin => 0)
|
9
|
+
command_list.add ListItem.new("Index",
|
10
|
+
:click => lambda{app.visit(INDEX_PAGE)},
|
11
|
+
:bullet => List::STAR_BULLET)
|
12
|
+
command_list.add HorizontalRule.new(:width => opt[:width])
|
13
|
+
command_list.add ListItem.new("Unordered Lists",
|
14
|
+
:click => lambda {app.visit(UNORDERED_LIST_PAGE)},
|
15
|
+
:bullet => List::CIRCLE_BULLET)
|
16
|
+
command_list.add ListItem.new("Ordered Lists",
|
17
|
+
:click => lambda {app.visit(ORDERED_LIST_PAGE)},
|
18
|
+
:bullet => List::CIRCLE_BULLET)
|
19
|
+
command_list.add ListItem.new("DropDownMenus",
|
20
|
+
:click => lambda {app.visit(DROP_DOWN_MENU_PAGE)},
|
21
|
+
:bullet => List::CIRCLE_BULLET)
|
22
|
+
command_list.show
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'action'
|
2
|
+
require 'nav'
|
3
|
+
require 'dd_menu_widget'
|
4
|
+
|
5
|
+
class DropDownMenuAction < Action
|
6
|
+
include Nav
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super
|
10
|
+
@widget = DDMenuWidget.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute()
|
14
|
+
app.info "#{self.class.name}.execute"
|
15
|
+
|
16
|
+
page_layout do
|
17
|
+
@widget.app = app
|
18
|
+
@view_area = @widget.show(VIEW_AREA_OPTS)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class DDMenuWidget
|
2
|
+
include Widget
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
end
|
6
|
+
|
7
|
+
def show(opt={})
|
8
|
+
app.info "#{self.class.name}.show"
|
9
|
+
app.stack(opt) do
|
10
|
+
app.para "The left column has active links with right click for drop down menu."
|
11
|
+
app.para "The right column has hover activation for the drop down menu."
|
12
|
+
app.para "Both columns close the menu when the mouse leaves it."
|
13
|
+
app.flow do
|
14
|
+
app.stack(:width => 100) do
|
15
|
+
list = UnorderedList.new(app)
|
16
|
+
numbers = %w(one two three four five).collect do |item|
|
17
|
+
ListItem.new(item,
|
18
|
+
:click => lambda{alert("#{item} was clicked")})
|
19
|
+
end
|
20
|
+
%w(alpha bravo charlie delta echo foxtrot).each do |item|
|
21
|
+
list.add(ListItem.new(item,
|
22
|
+
:menu_items => numbers,
|
23
|
+
:menu_trigger => DropDownMenuWidget::RIGHT_BUTTON,
|
24
|
+
:menu_options => {:width => 70},
|
25
|
+
:click => lambda{alert("#{item} was clicked")},
|
26
|
+
:bullet => List::CIRCLE_BULLET
|
27
|
+
))
|
28
|
+
end
|
29
|
+
list.show
|
30
|
+
end
|
31
|
+
app.stack(:width => 100) do
|
32
|
+
list = UnorderedList.new(app)
|
33
|
+
numbers = %w(six seven eight nine).collect do |item|
|
34
|
+
ListItem.new(item,
|
35
|
+
:click => lambda{alert("#{item} was clicked")})
|
36
|
+
end
|
37
|
+
%w(golf hotel india juliet kilo lima).each do |item|
|
38
|
+
list.add(ListItem.new(item,
|
39
|
+
:menu_items => numbers,
|
40
|
+
:menu_trigger => DropDownMenuWidget::HOVER,
|
41
|
+
:menu_options => {:width => 70},
|
42
|
+
:bullet => List::PLUS_BULLET
|
43
|
+
))
|
44
|
+
end
|
45
|
+
list.show
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/bin/env shoes
|
2
|
+
|
3
|
+
Shoes.setup do
|
4
|
+
# gem 'ruby-debug'
|
5
|
+
end
|
6
|
+
|
7
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'shoeshine')
|
8
|
+
|
9
|
+
require 'nav'
|
10
|
+
require 'action'
|
11
|
+
require 'dd_menu_action'
|
12
|
+
require 'index_action'
|
13
|
+
require 'ordered_list_action'
|
14
|
+
require 'unordered_list_action'
|
15
|
+
|
16
|
+
class ListExample < Shoes
|
17
|
+
include Nav
|
18
|
+
|
19
|
+
# a little meta programming to setup the three parts to each page like:
|
20
|
+
#
|
21
|
+
# FOO = '/foo'
|
22
|
+
# page_def FOO, :foo, FooAction
|
23
|
+
#
|
24
|
+
# yeilds:
|
25
|
+
#
|
26
|
+
# url '/foo', :foo
|
27
|
+
# @@actions[:foo] = FooAction
|
28
|
+
# def foo
|
29
|
+
# run_action(:foo)
|
30
|
+
# end
|
31
|
+
class << self
|
32
|
+
def page_def(page, name, klass)
|
33
|
+
class_eval "url '#{page.to_s}', :#{name.to_s}"
|
34
|
+
class_eval "@@actions[:#{name.to_s}] = #{klass}.new"
|
35
|
+
class_eval "def #{name.to_s}; run_action(:#{name.to_s}); end"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# @@actions instance must be before any page_def statements
|
40
|
+
@@actions = {}
|
41
|
+
|
42
|
+
# define our pages
|
43
|
+
page_def INDEX_PAGE, :index, IndexAction
|
44
|
+
page_def UNORDERED_LIST_PAGE, :ul, UnorderedListAction
|
45
|
+
page_def ORDERED_LIST_PAGE, :ol, OrderedListAction
|
46
|
+
page_def DROP_DOWN_MENU_PAGE, :drop_down_menu, DropDownMenuAction
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def run_action(action, *args)
|
51
|
+
a = @@actions[action]
|
52
|
+
a.app = self
|
53
|
+
a.execute(*args)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# start the GUI
|
58
|
+
Shoes.app(:title => 'Shoeshine Examples', :width => 800, :resizable => true)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'action'
|
2
|
+
require 'nav'
|
3
|
+
require 'index_widget'
|
4
|
+
|
5
|
+
class IndexAction < Action
|
6
|
+
include Nav
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super
|
10
|
+
@widget = IndexWidget.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute()
|
14
|
+
app.info "#{self.class.name}.execute"
|
15
|
+
|
16
|
+
page_layout do
|
17
|
+
@widget.app = app
|
18
|
+
@view_area = @widget.show(VIEW_AREA_OPTS)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class IndexWidget
|
2
|
+
include Widget
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@welcome_message = <<END_WELCOME
|
6
|
+
Welcome to Shoeshine.
|
7
|
+
|
8
|
+
Shoeshine is a set of UI widgets for use with the shoes toolkit.
|
9
|
+
|
10
|
+
Simply select a page on the left to see the examples.
|
11
|
+
|
12
|
+
Have fun,
|
13
|
+
Roy
|
14
|
+
END_WELCOME
|
15
|
+
end
|
16
|
+
|
17
|
+
def show(opt={})
|
18
|
+
app.stack(opt) do
|
19
|
+
app.para @welcome_message
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/examples/nav.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'action'
|
2
|
+
require 'nav'
|
3
|
+
require 'ordered_list_widget'
|
4
|
+
|
5
|
+
class OrderedListAction < Action
|
6
|
+
include Nav
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super
|
10
|
+
@widget = OrderedListWidget.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute()
|
14
|
+
app.info "#{self.class.name}.execute"
|
15
|
+
|
16
|
+
page_layout do
|
17
|
+
@widget.app = app
|
18
|
+
@view_area = @widget.show(VIEW_AREA_OPTS)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class PageWidget
|
2
|
+
include Widget
|
3
|
+
|
4
|
+
def show(opt={})
|
5
|
+
@gutter = app.gutter
|
6
|
+
app.background app.palegreen
|
7
|
+
app.style(Shoes::Link, :underline => false, :stroke => app.blue)
|
8
|
+
app.style(Shoes::LinkHover, :underline => true, :stroke => app.red)
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'shoeshine/widget'
|
2
|
+
class TitleWidget
|
3
|
+
include Widget
|
4
|
+
|
5
|
+
def show
|
6
|
+
app.stack(:width => '100%') do
|
7
|
+
app.background app.gradient(app.rgb(0, 0, 255), app.rgb(0, 255, 255), :angle => 135)
|
8
|
+
app.title("Shoeshine Examples", :align => 'center')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'action'
|
2
|
+
require 'nav'
|
3
|
+
require 'unordered_list_widget'
|
4
|
+
|
5
|
+
class UnorderedListAction < Action
|
6
|
+
include Nav
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super
|
10
|
+
@widget = UnorderedListWidget.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute()
|
14
|
+
app.info "#{self.class.name}.execute"
|
15
|
+
|
16
|
+
page_layout do
|
17
|
+
@widget.app = app
|
18
|
+
@view_area = @widget.show(VIEW_AREA_OPTS)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'shoeshine/widget'
|
2
|
+
|
3
|
+
class UnorderedListWidget
|
4
|
+
include Widget
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
end
|
8
|
+
|
9
|
+
def show(opt={})
|
10
|
+
app.stack(opt) do
|
11
|
+
app.flow do
|
12
|
+
app.para "Various bullets"
|
13
|
+
list_one({})
|
14
|
+
list_one({:bullet => List::CIRCLE_BULLET})
|
15
|
+
list_one({:bullet => List::STAR_BULLET})
|
16
|
+
list_one({:bullet => List::PLUS_BULLET})
|
17
|
+
end
|
18
|
+
app.flow(opt) do
|
19
|
+
app.para "With links"
|
20
|
+
list_two({})
|
21
|
+
list_two({:bullet => List::CIRCLE_BULLET})
|
22
|
+
list_two({:bullet => List::STAR_BULLET})
|
23
|
+
list_two({:bullet => List::PLUS_BULLET})
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def list_one(options)
|
29
|
+
app.stack({:width => 80}) do
|
30
|
+
list = UnorderedList.new(app, options)
|
31
|
+
%w(alpha bravo charlie delta echo foxtrot).each do |item|
|
32
|
+
list.add(ListItem.new(item))
|
33
|
+
end
|
34
|
+
list.show
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def list_two(options)
|
39
|
+
app.stack({:width => 80}) do
|
40
|
+
list = UnorderedList.new(app, options)
|
41
|
+
%w(alpha bravo charlie delta echo foxtrot).each do |item|
|
42
|
+
list.add(ListItem.new(item, :click => lambda{alert("#{item} clicked")}))
|
43
|
+
end
|
44
|
+
list.show
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'shoeshine/list_item'
|
2
|
+
require 'shoeshine/widget'
|
3
|
+
class DropDownMenuWidget
|
4
|
+
include Widget
|
5
|
+
|
6
|
+
LEFT_BUTTON = 1
|
7
|
+
MIDDLE_BUTTON = 2
|
8
|
+
RIGHT_BUTTON = 4
|
9
|
+
HOVER = 8
|
10
|
+
|
11
|
+
# app => Shoes.app
|
12
|
+
# title_item => instance that responds to either ListItem.as_value(app) or .to_s
|
13
|
+
# menu_items => Array of ListItem instances
|
14
|
+
# options => Hash may include:
|
15
|
+
# :background => pattern for drop down menu item background
|
16
|
+
# :border => pattern for drop down menu item background
|
17
|
+
# other slot options such as :width, :margin, ...
|
18
|
+
def initialize(app, title_item, activation_trigger, menu_items, options={})
|
19
|
+
self.app = app
|
20
|
+
@title_item = title_item
|
21
|
+
@trigger = activation_trigger
|
22
|
+
@menu_items = menu_items
|
23
|
+
@options = options
|
24
|
+
@activated = false
|
25
|
+
@activated_items = []
|
26
|
+
@stack_opts = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
# show the widget, initially in the deactivated (collapsed) state
|
30
|
+
# opts => same as initialize's options
|
31
|
+
def show(opts={})
|
32
|
+
@stack_opts ||= {:margin => 0}.merge(opts).merge(@options)
|
33
|
+
@slot = app.stack(@stack_opts) { show_item }
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
# show the menu
|
39
|
+
def activate
|
40
|
+
@menu_items.each do |item|
|
41
|
+
@slot.append do
|
42
|
+
@activated_items << app.flow do
|
43
|
+
app.background(@stack_opts[:background]) unless @stack_opts[:background].nil?
|
44
|
+
app.border(@stack_opts[:border]) unless @stack_opts[:border].nil?
|
45
|
+
app.para(item.as_value(app), :margin => 5)
|
46
|
+
end
|
47
|
+
app.leave {deactivate}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# remove the menu
|
53
|
+
def deactivate
|
54
|
+
unless @activated_items.empty?
|
55
|
+
@activated_items.each do |item|
|
56
|
+
item.remove
|
57
|
+
end
|
58
|
+
@activated_items.clear
|
59
|
+
@slot.clear { show_item }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# used by both show and deactivate to show the item with
|
64
|
+
# the popup hooked to the right mouse button.
|
65
|
+
def show_item
|
66
|
+
if @title_item.respond_to? "as_value"
|
67
|
+
value = @title_item.as_value(app)
|
68
|
+
else
|
69
|
+
value = @title_item.to_s
|
70
|
+
end
|
71
|
+
app.para value, :margin => 0
|
72
|
+
if((@trigger & HOVER) == HOVER)
|
73
|
+
app.hover do
|
74
|
+
activate if @activated_items.empty?
|
75
|
+
end
|
76
|
+
end
|
77
|
+
if((@trigger & (LEFT_BUTTON | MIDDLE_BUTTON | RIGHT_BUTTON)) > 0)
|
78
|
+
app.click do |button, top, left|
|
79
|
+
if trigger_fired?(button, @trigger)
|
80
|
+
@activated_items.empty? ? activate : deactivate
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def trigger_fired?(button, trigger)
|
87
|
+
result = false
|
88
|
+
result = true if (button == 1) && (trigger & LEFT_BUTTON != 0)
|
89
|
+
result = true if (button == 2) && (trigger & MIDDLE_BUTTON != 0)
|
90
|
+
result = true if (button == 3) && (trigger & RIGHT_BUTTON != 0)
|
91
|
+
result
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class HorizontalRule
|
2
|
+
include Widget
|
3
|
+
|
4
|
+
def initialize(opts={})
|
5
|
+
@options = opts
|
6
|
+
@options ||= {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def show(opts={})
|
10
|
+
show_opts = @options.merge(opts)
|
11
|
+
slot = app.flow(:width => show_opts[:width]) do
|
12
|
+
left = 5
|
13
|
+
right = show_opts[:width] - 10
|
14
|
+
app.rect(left, 0, right, 1)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class List
|
2
|
+
STAR_BULLET = :star
|
3
|
+
CIRCLE_BULLET = :circle
|
4
|
+
PLUS_BULLET = :plus
|
5
|
+
SPACE_BULLET = :space
|
6
|
+
|
7
|
+
BULLETS = {
|
8
|
+
:star => lambda{|app| app.star(-3,13,5,6,3)},
|
9
|
+
:circle => lambda{|app| app.oval(-7,10,7)},
|
10
|
+
:plus => lambda do |app|
|
11
|
+
# rect(x,y,w,h) NOTE, docs are wrong
|
12
|
+
length = 9
|
13
|
+
beam = 1
|
14
|
+
app.rect(-5,8,beam,length,1) # vertical bar
|
15
|
+
app.rect(-9,12,length,beam,1) # horizontal bar
|
16
|
+
end,
|
17
|
+
:space => lambda {|app| }
|
18
|
+
}
|
19
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
class ListItem
|
2
|
+
include Widget
|
3
|
+
|
4
|
+
attr_reader :options
|
5
|
+
|
6
|
+
def initialize(text, opts={})
|
7
|
+
@text = text
|
8
|
+
@options = opts
|
9
|
+
@options ||= {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def show(list_options={})
|
13
|
+
item_opts = self.options
|
14
|
+
right = (list_options[:margin_right].nil? ? 0 : list_options[:margin_right])
|
15
|
+
left = 10
|
16
|
+
bullet = @options[:bullet] || item_opts[:bullet] || list_options[:bullet]
|
17
|
+
icon = @options[:image] || item_opts[:image] || list_options[:image]
|
18
|
+
menu_items = @options[:menu_items] || item_opts[:menu_items] || list_options[:menu_items]
|
19
|
+
indent = (bullet.nil? ? 0 : 15)
|
20
|
+
app.flow(:margin_left => indent) do
|
21
|
+
unless icon.nil?
|
22
|
+
icon_image = app.image icon
|
23
|
+
indent = icon_image.full_width + 5
|
24
|
+
else
|
25
|
+
unless bullet.nil?
|
26
|
+
indent = 15
|
27
|
+
List::BULLETS[bullet].call(app)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
app.stack do
|
31
|
+
bg = item_opts[:background] || list_options[:background]
|
32
|
+
unless bg.nil?
|
33
|
+
app.background(bg, :margin_left => left)
|
34
|
+
left += 5
|
35
|
+
end
|
36
|
+
unless menu_items.nil?
|
37
|
+
menu_options = {
|
38
|
+
:margin_top => 4,
|
39
|
+
:margin_left => left,
|
40
|
+
:margin_right => right,
|
41
|
+
:margin_bottom => 0,
|
42
|
+
:background => app.gainsboro,
|
43
|
+
:border => app.gray
|
44
|
+
}.merge(@options[:menu_options] || item_opts[:menu_options] || list_options[:menu_options] || {})
|
45
|
+
trigger = @options[:menu_trigger] || DropDownMenuWidget::RIGHT_BUTTON
|
46
|
+
menu = DropDownMenuWidget.new(app, self, trigger, menu_items, menu_options)
|
47
|
+
menu.show
|
48
|
+
else
|
49
|
+
app.para(self.as_value(app), :margin_left => left, :margin_right => right, :margin_bottom => 0)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def as_value(app)
|
56
|
+
result = ''
|
57
|
+
if @options[:click].nil?
|
58
|
+
result = @text
|
59
|
+
else
|
60
|
+
result = app.link(@text, :click => @options[:click])
|
61
|
+
end
|
62
|
+
result || ''
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class UnorderedList < List
|
2
|
+
include Widget
|
3
|
+
|
4
|
+
public
|
5
|
+
|
6
|
+
def initialize(app, list_opts={})
|
7
|
+
self.app = app
|
8
|
+
@list_opts = list_opts
|
9
|
+
@list_opts ||= {}
|
10
|
+
@list_items = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def add(list_item)
|
14
|
+
@list_items << list_item
|
15
|
+
end
|
16
|
+
|
17
|
+
# list_opts => {
|
18
|
+
# :bullet => one_of(BULLETS.keys),
|
19
|
+
# :background => app.background argument
|
20
|
+
# }
|
21
|
+
def show(opts={})
|
22
|
+
list_options = {:margin_bottom => 10}.merge(@list_opts.merge(opts)) unless opts.nil?
|
23
|
+
|
24
|
+
app.stack(list_options) do
|
25
|
+
@list_items.each do |item|
|
26
|
+
item.app = app
|
27
|
+
item.show @list_opts
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/lib/shoeshine.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
APP_ENV = "development" unless defined? APP_ENV
|
2
|
+
$:.push(File.join(File.dirname(__FILE__)))
|
3
|
+
# require 'yaml'
|
4
|
+
# require 'logger'
|
5
|
+
# require 'singleton'
|
6
|
+
# require 'ruby-debug'
|
7
|
+
|
8
|
+
puts "shoeshine"
|
9
|
+
|
10
|
+
require 'shoeshine/widget'
|
11
|
+
require 'shoeshine/list'
|
12
|
+
require 'shoeshine/list_item'
|
13
|
+
require 'shoeshine/unordered_list'
|
14
|
+
require 'shoeshine/drop_down_menu'
|
15
|
+
require 'shoeshine/horizontal_rule'
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "DropDownMenuWidget" do
|
4
|
+
before(:each) do
|
5
|
+
@menu = DropDownMenuWidget.new(nil, nil, nil, nil)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should trigger on left button" do
|
9
|
+
button = 1
|
10
|
+
trigger = DropDownMenuWidget::LEFT_BUTTON
|
11
|
+
@menu.send('trigger_fired?', button, trigger).should be_true
|
12
|
+
end
|
13
|
+
it "should trigger on middle button" do
|
14
|
+
button = 2
|
15
|
+
trigger = DropDownMenuWidget::MIDDLE_BUTTON
|
16
|
+
@menu.send('trigger_fired?', button, trigger).should be_true
|
17
|
+
end
|
18
|
+
it "should trigger on right button" do
|
19
|
+
button = 3
|
20
|
+
trigger = DropDownMenuWidget::RIGHT_BUTTON
|
21
|
+
@menu.send('trigger_fired?', button, trigger).should be_true
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should not trigger on left button" do
|
25
|
+
button = 1
|
26
|
+
trigger = DropDownMenuWidget::MIDDLE_BUTTON | DropDownMenuWidget::RIGHT_BUTTON
|
27
|
+
@menu.send('trigger_fired?', button, trigger).should be_false
|
28
|
+
end
|
29
|
+
it "should not trigger on middle button" do
|
30
|
+
button = 2
|
31
|
+
trigger = DropDownMenuWidget::LEFT_BUTTON | DropDownMenuWidget::RIGHT_BUTTON
|
32
|
+
@menu.send('trigger_fired?', button, trigger).should be_false
|
33
|
+
end
|
34
|
+
it "should not trigger on right button" do
|
35
|
+
button = 3
|
36
|
+
trigger = DropDownMenuWidget::LEFT_BUTTON | DropDownMenuWidget::MIDDLE_BUTTON
|
37
|
+
@menu.send('trigger_fired?', button, trigger).should be_false
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should trigger on either left or middle but not right button" do
|
41
|
+
trigger = DropDownMenuWidget::LEFT_BUTTON | DropDownMenuWidget::MIDDLE_BUTTON
|
42
|
+
(@menu.send('trigger_fired?', 1, trigger).should be_true) &&
|
43
|
+
(@menu.send('trigger_fired?', 2, trigger).should be_true) &&
|
44
|
+
(@menu.send('trigger_fired?', 3, trigger).should be_false)
|
45
|
+
end
|
46
|
+
it "should trigger on either left or right but not middle button" do
|
47
|
+
trigger = DropDownMenuWidget::LEFT_BUTTON | DropDownMenuWidget::RIGHT_BUTTON
|
48
|
+
(@menu.send('trigger_fired?', 1, trigger).should be_true) &&
|
49
|
+
(@menu.send('trigger_fired?', 2, trigger).should be_false) &&
|
50
|
+
(@menu.send('trigger_fired?', 3, trigger).should be_true)
|
51
|
+
end
|
52
|
+
it "should trigger on either middle or right but not left button" do
|
53
|
+
trigger = DropDownMenuWidget::MIDDLE_BUTTON | DropDownMenuWidget::RIGHT_BUTTON
|
54
|
+
(@menu.send('trigger_fired?', 1, trigger).should be_false) &&
|
55
|
+
(@menu.send('trigger_fired?', 2, trigger).should be_true) &&
|
56
|
+
(@menu.send('trigger_fired?', 3, trigger).should be_true)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should trigger on left, middle or right" do
|
60
|
+
trigger = DropDownMenuWidget::LEFT_BUTTON | DropDownMenuWidget::MIDDLE_BUTTON | DropDownMenuWidget::RIGHT_BUTTON
|
61
|
+
(@menu.send('trigger_fired?', 1, trigger).should be_true) &&
|
62
|
+
(@menu.send('trigger_fired?', 2, trigger).should be_true) &&
|
63
|
+
(@menu.send('trigger_fired?', 3, trigger).should be_true)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should not trigger when button is out of range on left, middle or right" do
|
67
|
+
trigger = DropDownMenuWidget::MIDDLE_BUTTON | DropDownMenuWidget::RIGHT_BUTTON
|
68
|
+
(@menu.send('trigger_fired?', 0, trigger).should be_false) &&
|
69
|
+
(@menu.send('trigger_fired?', 4, trigger).should be_false) &&
|
70
|
+
(@menu.send('trigger_fired?', 8, trigger).should be_false)
|
71
|
+
end
|
72
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: royw-shoeshine
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Roy Wright
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-04-30 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: roy@wright.org
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- LICENSE
|
24
|
+
- README.rdoc
|
25
|
+
files:
|
26
|
+
- LICENSE
|
27
|
+
- README.rdoc
|
28
|
+
- Rakefile
|
29
|
+
- VERSION.yml
|
30
|
+
- examples/action.rb
|
31
|
+
- examples/command_widget.rb
|
32
|
+
- examples/dd_menu_action.rb
|
33
|
+
- examples/dd_menu_widget.rb
|
34
|
+
- examples/example_app.rb
|
35
|
+
- examples/index_action.rb
|
36
|
+
- examples/index_widget.rb
|
37
|
+
- examples/nav.rb
|
38
|
+
- examples/ordered_list_action.rb
|
39
|
+
- examples/ordered_list_widget.rb
|
40
|
+
- examples/page_widget.rb
|
41
|
+
- examples/title_widget.rb
|
42
|
+
- examples/unordered_list_action.rb
|
43
|
+
- examples/unordered_list_widget.rb
|
44
|
+
- lib/shoeshine.rb
|
45
|
+
- lib/shoeshine/drop_down_menu.rb
|
46
|
+
- lib/shoeshine/horizontal_rule.rb
|
47
|
+
- lib/shoeshine/list.rb
|
48
|
+
- lib/shoeshine/list_item.rb
|
49
|
+
- lib/shoeshine/unordered_list.rb
|
50
|
+
- lib/shoeshine/widget.rb
|
51
|
+
- spec/drop_down_menu_spec.rb
|
52
|
+
- spec/spec_helper.rb
|
53
|
+
has_rdoc: true
|
54
|
+
homepage: http://github.com/royw/shoeshine
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options:
|
57
|
+
- --charset=UTF-8
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: "0"
|
65
|
+
version:
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: "0"
|
71
|
+
version:
|
72
|
+
requirements: []
|
73
|
+
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 1.2.0
|
76
|
+
signing_key:
|
77
|
+
specification_version: 2
|
78
|
+
summary: TODO
|
79
|
+
test_files:
|
80
|
+
- spec/spec_helper.rb
|
81
|
+
- spec/drop_down_menu_spec.rb
|
82
|
+
- examples/example_app.rb
|
83
|
+
- examples/dd_menu_action.rb
|
84
|
+
- examples/nav.rb
|
85
|
+
- examples/title_widget.rb
|
86
|
+
- examples/dd_menu_widget.rb
|
87
|
+
- examples/unordered_list_action.rb
|
88
|
+
- examples/ordered_list_widget.rb
|
89
|
+
- examples/ordered_list_action.rb
|
90
|
+
- examples/index_action.rb
|
91
|
+
- examples/index_widget.rb
|
92
|
+
- examples/page_widget.rb
|
93
|
+
- examples/action.rb
|
94
|
+
- examples/unordered_list_widget.rb
|
95
|
+
- examples/command_widget.rb
|