]> git.cworth.org Git - sup/blob - lib/sup/colormap.rb
moved evertying to devel
[sup] / lib / sup / colormap.rb
1 require "curses"
2
3 module Redwood
4
5 class Colormap
6   @@instance = nil
7
8   CURSES_COLORS = [Curses::COLOR_BLACK, Curses::COLOR_RED, Curses::COLOR_GREEN,
9                    Curses::COLOR_YELLOW, Curses::COLOR_BLUE,
10                    Curses::COLOR_MAGENTA, Curses::COLOR_CYAN,
11                    Curses::COLOR_WHITE]
12   NUM_COLORS = 15
13   
14   def initialize
15     raise "only one instance can be created" if @@instance
16     @@instance = self
17     @entries = {}
18     @color_pairs = {[Curses::COLOR_WHITE, Curses::COLOR_BLACK] => 0}
19     @users = []
20     @next_id = 0
21     yield self if block_given?
22     @entries[highlight_sym(:none)] = highlight_for(Curses::COLOR_WHITE,
23                                                    Curses::COLOR_BLACK,
24                                                    []) + [nil]
25   end
26
27   def add sym, fg, bg, *attrs
28     raise ArgumentError, "color for #{sym} already defined" if
29       @entries.member? sym
30     raise ArgumentError, "color '#{fg}' unknown" unless CURSES_COLORS.include? fg
31     raise ArgumentError, "color '#{bg}' unknown" unless CURSES_COLORS.include? bg
32
33     @entries[sym] = [fg, bg, attrs, nil]
34     @entries[highlight_sym(sym)] = highlight_for(fg, bg, attrs) + [nil]
35   end
36
37   def highlight_sym sym
38     "#{sym}_highlight".intern
39   end
40
41   def highlight_for fg, bg, attrs
42     hfg =
43       case fg
44       when Curses::COLOR_BLUE
45         Curses::COLOR_WHITE
46       when Curses::COLOR_YELLOW, Curses::COLOR_GREEN
47         fg
48       else
49         Curses::COLOR_BLACK
50       end
51
52     hbg = 
53       case bg
54       when Curses::COLOR_CYAN
55         Curses::COLOR_YELLOW
56       else
57         Curses::COLOR_CYAN
58       end
59
60     attrs =
61       if fg == Curses::COLOR_WHITE && attrs.include?(Curses::A_BOLD)
62         [Curses::A_BOLD]
63       else
64         case hfg
65         when Curses::COLOR_BLACK
66           []
67         else
68           [Curses::A_BOLD]
69         end
70       end
71     [hfg, hbg, attrs]
72   end
73
74   def color_for sym, highlight=false
75     sym = highlight_sym(sym) if highlight
76     return Curses::COLOR_BLACK if sym == :none
77     raise ArgumentError, "undefined color #{sym}" unless @entries.member? sym
78
79     ## if this color is cached, return it
80     fg, bg, attrs, color = @entries[sym]
81     return color if color
82
83     if(cp = @color_pairs[[fg, bg]])
84       ## nothing
85     else ## need to get a new colorpair
86       @next_id = (@next_id + 1) % NUM_COLORS
87       @next_id += 1 if @next_id == 0 # 0 is always white on black
88       id = @next_id
89       Redwood::log "colormap: for color #{sym}, using id #{id} -> #{fg}, #{bg}"
90       Curses.init_pair id, fg, bg or raise ArgumentError,
91         "couldn't initialize curses color pair #{fg}, #{bg} (key #{id})"
92
93       cp = @color_pairs[[fg, bg]] = Curses.color_pair(id)
94       ## delete the old mapping, if it exists
95       if @users[cp]
96         @users[cp].each do |usym|
97           Redwood::log "dropping color #{usym} (#{id})"
98           @entries[usym][3] = nil
99         end
100         @users[cp] = []
101       end
102     end
103
104     ## by now we have a color pair
105     color = attrs.inject(cp) { |color, attr| color | attr }
106     @entries[sym][3] = color # fill the cache
107     (@users[cp] ||= []) << sym # record entry as a user of that color pair
108     color
109   end
110
111   def self.instance; @@instance; end
112   def self.method_missing meth, *a
113     Colorcolors.new unless @@instance
114     @@instance.send meth, *a
115   end
116 end
117
118 end