ektoplayer 0.1.6 → 0.1.11

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.
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