File Coverage

blib/lib/Curses/Toolkit/Theme.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             #
2             # This file is part of Curses-Toolkit
3             #
4             # This software is copyright (c) 2011 by Damien "dams" Krotkine.
5             #
6             # This is free software; you can redistribute it and/or modify it under
7             # the same terms as the Perl 5 programming language system itself.
8             #
9 1     1   78 use warnings;
  1         2  
  1         32  
10 1     1   5 use strict;
  1         2  
  1         67  
11              
12             package Curses::Toolkit::Theme;
13             {
14             $Curses::Toolkit::Theme::VERSION = '0.211';
15             }
16              
17             # ABSTRACT: base class for widgets themes
18              
19 1     1   20 use Params::Validate qw(SCALAR ARRAYREF HASHREF CODEREF GLOB GLOBREF SCALARREF HANDLE BOOLEAN UNDEF validate validate_pos);
  1         1  
  1         104  
20 1     1   2095 use Curses;
  0            
  0            
21              
22              
23             # service color initialization;
24             my $color_initialized = 0;
25              
26             sub new {
27             my $class = shift;
28             my ($widget) = validate_pos( @_, { isa => 'Curses::Toolkit::Widget' } );
29             $class eq __PACKAGE__ and die "abstract class";
30             my $self = bless { widget => $widget }, $class;
31             $self->set_property( ref $widget, $self->_get_default_properties( ref $widget ) );
32             $color_initialized or $class->_init_themes_colors();
33             return $self;
34             }
35              
36             sub default_fgcolor { 'white' }
37             sub default_bgcolor { 'black' }
38              
39             my %colors_to_pair;
40              
41             sub _init_themes_colors {
42             my ($class) = @_;
43             if ( has_colors() ) {
44              
45             # default color 0, can't be changed.
46             $colors_to_pair{'white'}{'black'} = 0;
47              
48             # define all posisble color
49             my $counter = 1;
50             my %colors_to_curses_colors = (
51             black => COLOR_BLACK,
52             red => COLOR_RED,
53             green => COLOR_GREEN,
54             yellow => COLOR_YELLOW,
55             blue => COLOR_BLUE,
56             magenta => COLOR_MAGENTA,
57             cyan => COLOR_CYAN,
58             white => COLOR_WHITE,
59             );
60             my @color = keys %colors_to_curses_colors;
61             foreach my $fgcolor (@color) {
62             foreach my $bgcolor (@color) {
63             $fgcolor eq 'white' && $bgcolor eq 'black'
64             and next;
65             init_pair( $counter, $colors_to_curses_colors{$fgcolor}, $colors_to_curses_colors{$bgcolor} );
66             $colors_to_pair{$fgcolor}{$bgcolor} = COLOR_PAIR($counter);
67             $counter++;
68             }
69             }
70             $color_initialized = 1;
71             }
72             }
73              
74             sub _set_fgcolor {
75             my ( $self, $fgcolor ) = @_;
76             $self->{_fgcolor} = $fgcolor;
77             return $self;
78             }
79              
80             sub _set_bgcolor {
81             my ( $self, $bgcolor ) = @_;
82             $self->{_bgcolor} = $bgcolor;
83             my ( $package, $filename, $line ) = caller;
84             return $self;
85             }
86              
87             sub _set_colors {
88             my ( $self, $fgcolor, $bgcolor ) = @_;
89             $self->_set_bgcolor($bgcolor);
90             $self->_set_fgcolor($fgcolor);
91             return $self;
92             }
93              
94             sub _get_fg_color { shift->{_fgcolor}; }
95              
96             sub _get_bg_color { shift->{_bgcolor}; }
97              
98             sub _get_color_pair {
99             my ($self) = @_;
100             has_colors()
101             or die "Color is not supported by your terminal";
102             return $colors_to_pair{ $self->_get_fg_color() }{ $self->_get_bg_color() };
103             }
104              
105              
106              
107             sub set_property {
108             my $self = shift;
109             my $class_name = shift;
110             my $definition = $class_name->_get_theme_properties_definition();
111             my ( $property_name, $value ) = @_;
112             my $parameters = {};
113             if ( ref $property_name eq 'HASH' && !defined $value ) {
114             $parameters = $property_name;
115             } elsif ( !ref $property_name ) {
116             $parameters = { $property_name => $value };
117             }
118              
119             my @parameters = %$parameters;
120             my %params = validate( @parameters, $definition );
121              
122             @{ $self->{property}{$class_name} }{ keys %params } = values %params;
123             return $self;
124             }
125              
126              
127             sub get_property {
128             my $self = shift;
129             my ( $class_name, $property_name ) = validate_pos( @_, 1, 0 );
130             my $properties = $self->{property}{$class_name};
131             defined $properties or $properties = {};
132             if ( defined $property_name ) {
133             return $properties->{$property_name};
134             }
135             return ( {%$properties} );
136             }
137              
138              
139             sub get_widget {
140             my ($self) = @_;
141             defined $self->{widget} or return;
142             return $self->{widget};
143             }
144              
145              
146             sub get_window {
147             my ($self) = @_;
148             my $widget = $self->get_widget()
149             or return;
150             my $window = $widget->get_window()
151             or return;
152             return $window;
153             }
154              
155              
156             sub get_root_window {
157             my ($self) = @_;
158             my $window = $self->get_window()
159             or return;
160             my $root_window = $window->get_root_window()
161             or return;
162             return $root_window;
163             }
164              
165              
166             sub get_shape {
167             my ($self) = @_;
168             my $shape = $self->get_widget->get_visible_shape();
169              
170             # my $root_window = $self->get_root_window()
171             # or return;
172             # my $shape = $root_window->get_shape()
173             # or return;
174              
175             return $shape;
176             }
177              
178              
179             sub is_in_shape {
180             my $self = shift;
181             my $shape = $self->get_shape()
182             or return;
183             return Curses::Toolkit::Object::Coordinates->new(@_)->is_inside($shape);
184             }
185              
186              
187             sub restrict_to_shape {
188             my $self = shift;
189             my %args = @_;
190             my $attr = delete $args{attr} || {};
191             my $c = Curses::Toolkit::Object::Coordinates->new(%args);
192             $attr->{no_shape_restriction}
193             and return $c;
194             my $shape = $self->get_shape()
195             or return;
196             return $c->restrict_to($shape);
197             }
198              
199              
200             sub curses {
201             my ( $self, $attr ) = @_;
202             my $caller = ( caller(1) )[3];
203             my $type = uc( ( split( '_', $caller ) )[1] );
204             $self->_compute_attributes( $type, $attr );
205             return $self->_get_curses_handler();
206             }
207              
208             # gets the curses handler of the associated widget
209             #
210             # input : none
211             # output : a Curses object
212             sub _get_curses_handler {
213             my ($self) = @_;
214             return $self->get_widget()->_get_curses_handler();
215             }
216              
217             sub _compute_attributes {
218             my ( $self, $type, $attr ) = @_;
219              
220             # reset display attributes
221             $self->_get_curses_handler()->attrset(0);
222             $attr ||= {};
223             $self->_set_fgcolor( $self->default_fgcolor() );
224             $self->_set_bgcolor( $self->default_bgcolor() );
225              
226             # get the type of attributes we want, and call the method
227             my $method = $type . '_NORMAL';
228             $self->$method();
229             if ( ( $self->get_widget()->isa('Curses::Toolkit::Role::Focusable') && $self->get_widget()->is_focused() )
230             || delete $attr->{focused} )
231             {
232             $method = $type . '_FOCUSED';
233             $self->$method();
234             }
235             if ( delete $attr->{clicked} ) {
236             $method = $type . '_CLICKED';
237             $self->$method();
238             }
239              
240             # check if additional attributes need to be applied
241             if ( exists $attr->{bold} ) {
242             $attr->{bold} and $self->_attron(A_BOLD);
243             $attr->{bold} or $self->_attroff(A_BOLD);
244             }
245             if ( exists $attr->{reverse} ) {
246             $attr->{reverse} and $self->_attron(A_REVERSE);
247             $attr->{reverse} or $self->_attroff(A_REVERSE);
248             }
249             if ( exists $attr->{fgcolor} ) {
250             $self->_set_fgcolor( $attr->{fgcolor} );
251             }
252             if ( exists $attr->{bgcolor} ) {
253             $self->_set_bgcolor( $attr->{bgcolor} );
254             }
255             has_colors()
256             and $self->_get_curses_handler()->attron( $self->_get_color_pair() );
257             return;
258             }
259              
260             sub _attron {
261             my $self = shift;
262             $self->_get_curses_handler()->attron(@_);
263             return $self;
264             }
265              
266             sub _attroff {
267             my $self = shift;
268             $self->_get_curses_handler()->attroff(@_);
269             }
270              
271             sub _attrset {
272             my $self = shift;
273             $self->_get_curses_handler()->attrset(@_);
274             }
275              
276             sub _addstr_with_tags {
277             my ( $self, $initial_attr, $x, $y, $text ) = @_;
278              
279             use Curses::Toolkit::Object::MarkupString;
280             ref $text
281             or $text = Curses::Toolkit::Object::MarkupString->new($text);
282              
283             my $struct = $text->get_attr_struct();
284              
285             # get the curses handler
286             my $curses = $self->_get_curses_handler();
287              
288             my $caller = ( caller(1) )[3];
289             my $type = uc( ( split( '_', $caller ) )[1] );
290              
291             foreach my $element (@$struct) {
292             my ( $char, @attrs ) = @$element;
293             $self->_compute_attributes( $type, $initial_attr );
294             my $value = 0;
295              
296              
297             my %weight_to_const = (
298             normal => A_NORMAL,
299             standout => A_STANDOUT,
300             underline => A_UNDERLINE,
301             reverse => A_REVERSE,
302             blink => A_BLINK,
303             dim => A_DIM,
304             bold => A_BOLD
305             );
306              
307             foreach my $attr (@attrs) {
308             my $weight = $attr->{weight};
309             if ( defined $weight && $weight ) {
310             my $v = $weight_to_const{$weight};
311             if ( defined $v ) {
312             $value = ( $value | $v );
313             } else {
314             warn
315             "WARNING : you used this string as value for the 'weight' attribute in one of the tags in your strings : '$weight'. However it's not supported. Available 'weight' values are : "
316             . join( ', ', keys %weight_to_const );
317             }
318             $weight eq 'normal'
319             and $value = 0;
320             }
321              
322             defined $attr->{fgcolor}
323             and $self->_set_fgcolor( $attr->{fgcolor} );
324             defined $attr->{bgcolor}
325             and $self->_set_bgcolor( $attr->{bgcolor} );
326             }
327             has_colors()
328             and $value = ( $value | $self->_get_color_pair() );
329             $curses->attron($value);
330             $curses->addstr( $y, $x, $char );
331             $x++;
332             }
333             return $self;
334             }
335              
336             1;
337              
338             __END__