ektoplayer 0.1.6 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +26 -12
  3. data/lib/ektoplayer/application.rb +6 -5
  4. data/lib/ektoplayer/bindings.rb +61 -55
  5. data/lib/ektoplayer/common.rb +19 -6
  6. data/lib/ektoplayer/compat.rb +3 -3
  7. data/lib/ektoplayer/config.rb +1 -11
  8. data/lib/ektoplayer/controllers/browser.rb +7 -5
  9. data/lib/ektoplayer/controllers/help.rb +1 -1
  10. data/lib/ektoplayer/controllers/info.rb +1 -1
  11. data/lib/ektoplayer/controllers/playlist.rb +24 -12
  12. data/lib/ektoplayer/icurses.rb +21 -0
  13. data/lib/ektoplayer/icurses/curses.rb +53 -0
  14. data/lib/ektoplayer/icurses/ffi_ncurses.rb +69 -0
  15. data/lib/ektoplayer/icurses/ncurses.rb +79 -0
  16. data/lib/ektoplayer/icurses/ncursesw.rb +1 -0
  17. data/lib/ektoplayer/icurses/sugar.rb +65 -0
  18. data/lib/ektoplayer/icurses/test.rb +99 -0
  19. data/lib/ektoplayer/models/player.rb +2 -2
  20. data/lib/ektoplayer/{mp3player.rb → players/mpg_portaudio_player.rb} +3 -3
  21. data/lib/ektoplayer/players/mpg_wrapper_player.rb +107 -0
  22. data/lib/ektoplayer/theme.rb +1 -6
  23. data/lib/ektoplayer/ui.rb +100 -129
  24. data/lib/ektoplayer/ui/colors.rb +14 -14
  25. data/lib/ektoplayer/ui/widgets.rb +4 -4
  26. data/lib/ektoplayer/ui/widgets/labelwidget.rb +1 -1
  27. data/lib/ektoplayer/ui/widgets/listwidget.rb +115 -46
  28. data/lib/ektoplayer/views/help.rb +7 -10
  29. data/lib/ektoplayer/views/info.rb +29 -38
  30. data/lib/ektoplayer/views/mainwindow.rb +2 -5
  31. data/lib/ektoplayer/views/playinginfo.rb +15 -20
  32. data/lib/ektoplayer/views/progressbar.rb +30 -10
  33. data/lib/ektoplayer/views/splash.rb +24 -25
  34. data/lib/ektoplayer/views/tabbar.rb +6 -5
  35. data/lib/ektoplayer/views/trackrenderer.rb +20 -14
  36. metadata +15 -47
  37. data/lib/ektoplayer/views/volumemeter.rb +0 -76
@@ -1,4 +1,4 @@
1
- require 'curses'
1
+ require_relative '../icurses'
2
2
 
3
3
  require_relative 'controller'
4
4
 
@@ -1,4 +1,4 @@
1
- require 'curses'
1
+ require_relative '../icurses'
2
2
 
3
3
  require_relative 'controller'
4
4
 
@@ -10,7 +10,7 @@ module Ektoplayer
10
10
 
11
11
  register = view_operations.with_register('playlist.')
12
12
  %w(up down page_up page_down top bottom
13
- search_up search_down search_next search_prev).
13
+ search_up search_down search_next search_prev toggle_selection).
14
14
  each { |op| register.(op, &@view.method(op)) }
15
15
 
16
16
  register.(:play) do
@@ -18,24 +18,36 @@ module Ektoplayer
18
18
  end
19
19
 
20
20
  register.(:reload) do
21
- operations.send(:'playlist.reload', view.selected)
21
+ view.get_selection.each do |index|
22
+ operations.send(:'playlist.reload', index)
23
+ end
22
24
  end
23
25
 
24
26
  register.(:download_album) do
25
- operations.send(:'playlist.download_album', view.selected)
27
+ view.get_selection.each do |index|
28
+ operations.send(:'playlist.download_album', index)
29
+ end
26
30
  end
27
31
 
28
32
  register.(:delete) do
29
- old_cursor, old_selected = view.cursor, view.selected
30
- operations.send(:'playlist.delete', old_selected)
31
- view.selected=(old_selected)
32
- view.force_cursorpos(old_cursor)
33
+ view.with_lock do
34
+ old_cursor, selection = view.cursor, view.get_selection
35
+
36
+ selection.each do
37
+ operations.send(:'playlist.delete', selection[0])
38
+ end
39
+
40
+ view.selected=(selection[0])
41
+ view.force_cursorpos(old_cursor)
42
+ end
33
43
  end
34
44
 
35
45
  register.(:goto_current) do
36
- if index = playlist.current_playing
37
- view.selected=(index)
38
- view.center()
46
+ view.with_lock do
47
+ if index = playlist.current_playing
48
+ view.selected=(index)
49
+ view.center()
50
+ end
39
51
  end
40
52
  end
41
53
 
@@ -43,14 +55,14 @@ module Ektoplayer
43
55
  view.mouse.on(65536) do view.up(5) end
44
56
  view.mouse.on(2097152) do view.down(5) end
45
57
 
46
- [Curses::BUTTON1_CLICKED, Curses::BUTTON2_CLICKED].
58
+ [ICurses::BUTTON1_CLICKED, ICurses::BUTTON2_CLICKED].
47
59
  each do |button|
48
60
  view.mouse.on(button) do |mevent|
49
61
  view.select_from_cursorpos(mevent.y)
50
62
  end
51
63
  end
52
64
 
53
- [Curses::BUTTON1_DOUBLE_CLICKED, Curses::BUTTON3_CLICKED].each do |btn|
65
+ [ICurses::BUTTON1_DOUBLE_CLICKED, ICurses::BUTTON3_CLICKED].each do |btn|
54
66
  view.mouse.on(btn) do |mevent|
55
67
  view.select_from_cursorpos(mevent.y)
56
68
  view_operations.send('playlist.play')
@@ -0,0 +1,21 @@
1
+ %w(ffi-ncurses ncursesw ncurses curses).each do |f|
2
+ begin
3
+ $USING_CURSES = f
4
+ require_relative "icurses/#{f}"
5
+ break
6
+ rescue LoadError
7
+ $USING_CURSES = nil
8
+ end
9
+ end
10
+
11
+ fail %{
12
+ No interface for ncurses found. Please install one of the following gems
13
+ - curses
14
+ - ffi-ncurses
15
+ - ncurses-ruby
16
+ - ncursesw
17
+
18
+ Maybe your distribution ships one of these already as a package.
19
+ } unless $USING_CURSES
20
+
21
+ require_relative 'icurses/sugar'
@@ -0,0 +1,53 @@
1
+ require 'curses'
2
+
3
+ module Curses
4
+ def Curses.initscr; init_screen end
5
+ def Curses.endwin; close_screen end
6
+
7
+ def Curses.newwin(*a) Curses::Window.new(*a) end
8
+ def Curses.newpad(*a) Curses::Pad.new(*a) end
9
+
10
+ class Window
11
+ def mvaddstr(y, x, s)
12
+ move(y, x)
13
+ addstr(s)
14
+ end
15
+
16
+ %w(curx cury maxx maxy begx begy).each do |method|
17
+ alias_method :"get#{method}", method.to_sym
18
+ end
19
+
20
+ alias :timeout :timeout=
21
+ alias :notimeout :nodelay= #todo
22
+ alias :nodelay :nodelay=
23
+
24
+ alias :mvwin :move # 'fix' this Gem
25
+ def move(y, x)
26
+ setpos(y, x)
27
+ end
28
+ end
29
+
30
+ class Pad < Window
31
+ alias :pnoutrefresh :refresh
32
+ end
33
+ end
34
+
35
+ module ICurses
36
+ include Curses
37
+
38
+ (Curses.public_methods - public_methods).each do |method|
39
+ define_singleton_method(method, &Curses.method(method))
40
+ end
41
+
42
+ def mousemask(mask, *a); Curses.mousemask(mask) end
43
+ module_function :mousemask
44
+
45
+ def getmouse(mevent=nil)
46
+ if mevent = Curses.getmouse()
47
+ return IMouseEvent.new(mevent)
48
+ end
49
+ end
50
+ module_function :getmouse
51
+
52
+ IWindow = Curses::Window
53
+ end
@@ -0,0 +1,69 @@
1
+ require 'ffi-ncurses'
2
+
3
+ module FFI::NCurses
4
+ alias_method :_newwin, :newwin
5
+ def newwin(*a)
6
+ IWindow.new(_newwin(*a))
7
+ end
8
+ module_function :newwin
9
+
10
+ alias_method :_newpad, :newpad
11
+ def newpad(*a)
12
+ IWindow.new(_newpad(*a))
13
+ end
14
+ module_function :newpad
15
+
16
+ alias_method :_stdscr, :stdscr
17
+ def stdscr
18
+ IWindow.new(_stdscr)
19
+ end
20
+ module_function :stdscr
21
+
22
+ alias_method :_mousemask, :mousemask
23
+ def mousemask(mask, *_)
24
+ _mousemask(mask, nil)
25
+ end
26
+ module_function :mousemask
27
+
28
+ alias_method :_getmouse, :getmouse
29
+ def getmouse(mevent=nil)
30
+ mevent = FFI::NCurses::Mouse::MEVENT.new
31
+ if _getmouse(mevent) > -1
32
+ return IMouseEvent.new(mevent)
33
+ end
34
+ end
35
+ module_function :getmouse
36
+
37
+
38
+ class Window
39
+ def initialize(w)
40
+ @w = w
41
+ end
42
+
43
+ FFI::NCurses.public_methods.each do |method|
44
+ if method =~ /^(mv)?w/
45
+ define_method(method) do |*args|
46
+ FFI::NCurses.send(method, @w, *args)
47
+ end
48
+
49
+ next if method =~ /win$/
50
+
51
+ define_method(method.to_s.sub(?w, '')) do |*args|
52
+ FFI::NCurses.send(method, @w, *args)
53
+ end
54
+ end
55
+ end
56
+
57
+ %w(getcurx getcury getmaxx getmaxy getbegx getbegy
58
+ keypad nodelay notimeout prefresh pnoutrefresh).each do |meth|
59
+
60
+ define_method(meth) do |*args|
61
+ FFI::NCurses.send(meth, @w, *args)
62
+ end
63
+ end
64
+ end
65
+
66
+ IWindow = Window
67
+ end
68
+
69
+ ICurses = FFI::NCurses
@@ -0,0 +1,79 @@
1
+ require $USING_CURSES
2
+
3
+ Ncurses.initscr
4
+
5
+ module Ncurses
6
+ class IWindow
7
+ def initialize(w)
8
+ @w = w
9
+ end
10
+
11
+ def getch
12
+ return Ncurses::wgetch(self)
13
+ y, x = Ncurses::getcury(self), Ncurses::getcurx(self)
14
+ c = Ncurses::wgetch(self)
15
+ Ncurses::wmove(self, y, x)
16
+ c
17
+ end
18
+
19
+ %w(getcurx getcury getmaxx getmaxy getbegx getbegy
20
+ keypad nodelay notimeout prefresh pnoutrefresh).each do |meth|
21
+ define_method(meth) do |*args|
22
+ Ncurses.send(meth, @w, *args)
23
+ end
24
+ end
25
+
26
+ Ncurses.public_methods.each do |meth|
27
+ if meth =~ /^(mv)?w/
28
+ define_method(meth) do |*args|
29
+ Ncurses.send(meth, @w, *args)
30
+ end
31
+
32
+ next if meth =~ /win$/
33
+
34
+ define_method(meth.to_s.sub(?w, '')) do |*args|
35
+ Ncurses.send(meth, @w, *args)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ module ICurses
43
+ include Ncurses
44
+
45
+ def method_missing(m, *a)
46
+ Ncurses.send(m, *a)
47
+ rescue NoMethodError
48
+ Ncurses.send(m.downcase, *a)
49
+ end
50
+ module_function :method_missing
51
+
52
+ def initscr; end # do nothing
53
+ module_function :initscr
54
+
55
+ def newwin(*a)
56
+ ICurses::IWindow.new( Ncurses.newwin(*a) )
57
+ end
58
+ module_function :newwin
59
+
60
+ def newpad(*a)
61
+ ICurses::IWindow.new( Ncurses.newpad(*a) )
62
+ end
63
+ module_function :newpad
64
+
65
+ def mousemask(mask, *_)
66
+ Ncurses.mousemask(mask, [])
67
+ end
68
+ module_function :mousemask
69
+
70
+ def getmouse(mevent=nil)
71
+ mevent = Ncurses::MEVENT.new
72
+ if Ncurses.getmouse(mevent) > -1
73
+ return IMouseEvent.new(mevent)
74
+ end
75
+ end
76
+ module_function :getmouse
77
+
78
+ IWindow = Ncurses::IWindow
79
+ end
@@ -0,0 +1 @@
1
+ require_relative 'ncurses'
@@ -0,0 +1,65 @@
1
+ module ICurses
2
+ class IMouseEvent
3
+ attr_accessor :x, :y, :z, :bstate
4
+
5
+ def initialize(mouse_event=nil)
6
+ from_mouse_event!(mouse_event)
7
+ end
8
+
9
+ def [](key) send(key) end
10
+ def []=(key, value) send("#{key}=", value) end
11
+
12
+ def from_mouse_event!(m)
13
+ @x, @y, @z, @bstate = m.x, m.y, m.z, m.bstate
14
+ rescue
15
+ @x, @y, @z, @bstate = m[:x], m[:y], m[:z], m[:bstate]
16
+ rescue
17
+ @x= @y= @z= @bstate = 0
18
+ end
19
+
20
+ def update!(x: nil, y: nil, z: nil, bstate: nil)
21
+ @x = x if x
22
+ @y = y if y
23
+ @z = z if z
24
+ @bstate = (bstate or @bstate)
25
+ end
26
+ end
27
+ end
28
+
29
+ module ICurses
30
+ %w(lines cols colors init_pair color_pair).each do |meth|
31
+ meth_up = meth.upcase
32
+
33
+ if not respond_to? meth
34
+ alias_method(meth, meth_up) rescue (
35
+ define_method(meth) do |*args|
36
+ method_missing(meth_up, *args)
37
+ end
38
+ )
39
+
40
+ module_function(meth)
41
+ elsif not respond_to? meth_up
42
+ alias_method(meth_up, meth) rescue (
43
+ define_method(meth_up) do |*args|
44
+ method_missing(meth, *args)
45
+ end
46
+ )
47
+ module_function(meth_up)
48
+ end
49
+ end
50
+
51
+ class IWindow
52
+ unless respond_to? :<<
53
+ alias_method(:<<, :addstr)
54
+ end
55
+
56
+ %w(curx cury maxx maxy begx begy).each do |meth|
57
+ full = 'get' + meth
58
+ if not respond_to? meth
59
+ alias_method(meth, full)
60
+ elsif not respond_to? full
61
+ alias_method(full, meth)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ unless ARGV[0]
4
+ %w(curses ncurses ncursesw ffi_curses).each do |i|
5
+ puts i
6
+ fail i unless system($0, i)
7
+ end
8
+ exit
9
+ end
10
+
11
+ $USING_CURSES = ARGV[0]
12
+ require_relative ARGV[0]
13
+ require_relative 'sugar'
14
+
15
+ begin
16
+ warn 'call: initscr'
17
+ ICurses.initscr
18
+
19
+ warn 'call: stdscr'
20
+ s = ICurses.stdscr
21
+ warn 'call: stdscr.clear, stdscr.refresh'
22
+ s.clear; s.refresh
23
+
24
+ warn 'call: newwin(0,0,0,0)'
25
+ w = ICurses.newwin(0,0,0,0)
26
+ warn 'call: win.erase'
27
+ w.erase
28
+
29
+ warn 'call: win.addstr, win.mvaddstr, win.move, win.getcurx, win.getcury'
30
+ w.addstr(ARGV[0])
31
+ w.mvaddstr(1,0, 'test 1')
32
+ w.move(2,0);
33
+ w.addstr('test 2')
34
+ x, y = w.getcurx, w.getcury
35
+ w.mvaddstr(y + 1, 0, 'test 3')
36
+
37
+ warn 'call win.getch'
38
+ w.getch
39
+
40
+ warn 'call: LINES COLS'
41
+ w.addstr("my term is #{ICurses.LINES} lines and #{ICurses.COLS} cols")
42
+
43
+ warn 'call: win.resize'
44
+ w.resize(50, 30)
45
+
46
+ warn 'call: win.refresh, win.noutrefresh'
47
+ w.refresh; w.noutrefresh
48
+
49
+ warn 'call: keypad(true)'
50
+ w.keypad(true)
51
+
52
+ warn 'call: timeout(-1)'
53
+ w.timeout(1000)
54
+
55
+ warn 'call: nodelay(false)'
56
+ w.nodelay(false)
57
+
58
+ warn 'call: notimeout(true)'
59
+ w.notimeout(true)
60
+
61
+ warn 'call: curs_set, nl, nonl, echo, noecho'
62
+ ICurses.curs_set(1); ICurses.curs_set(0)
63
+ ICurses.nl; ICurses.nonl
64
+ ICurses.echo; ICurses.noecho
65
+
66
+ warn 'call: mousemask'
67
+ ICurses.mousemask(ICurses::ALL_MOUSE_EVENTS, [])
68
+
69
+ # === Colors === #
70
+ warn 'call: start_color, use_default_colors, init_pair, attron, attroff'
71
+ ICurses.start_color
72
+ ICurses.use_default_colors
73
+ ICurses.init_pair(1, ICurses::COLOR_BLACK, ICurses::COLOR_GREEN)
74
+ w.attron(ICurses.color_pair(1))
75
+ w.addstr("my term is has #{ICurses.COLORS}")
76
+ w.attroff(ICurses.color_pair(1))
77
+
78
+ # === Sugar ===
79
+ warn 'call: <<'
80
+ w << 'sugar'
81
+
82
+ loop do
83
+ sleep 0.1
84
+ warn 'call getch()'
85
+ c = w.getch
86
+ unless c
87
+ warn "empty getch"
88
+ next
89
+ end
90
+ warn "returned #{c} (#{c.ord})"
91
+ ch = c.chr rescue ''
92
+ w.addstr("#{ch}")
93
+ break if ch == ?q
94
+ end
95
+ ensure
96
+ ICurses.endwin rescue puts $!
97
+ end
98
+
99
+ exit 0