our
$VERSION
= 0.05;
our
$AUTHORITY
=
'cpan:JHALLOCK'
;
Gtk2::Entry::,
interfaces
=> [
'Gtk2::CellEditable'
],
properties
=> [
Glib::ParamSpec->string(
'value'
,
'value'
,
'ISO format time string like 13:00'
,
''
,
Glib::G_PARAM_READWRITE
),
],
signals
=> {
value_changed
=> {
class_closure
=> \
&_do_value_changed
,
flags
=> [
'run-first'
] ,
return_type
=>
undef
,
param_types
=> [] ,
},
}
;
sub
INIT_INSTANCE {
my
$self
=
shift
;
$self
->signal_connect(
'key-press-event'
=> \
&_do_key_press_event
);
$self
->signal_connect(
'focus-out-event'
=> \
&_do_focus_out_event
);
}
sub
SET_PROPERTY {
my
(
$self
,
$pspec
,
$newval
) =
@_
;
my
$pname
=
$pspec
->get_name;
if
(
$pname
eq
'value'
) {
$newval
=
$self
->_parse_input(
$newval
);
if
(!
defined
$self
->{
$pname
} &&
defined
$newval
||
$self
->{
$pname
} ne
$newval
) {
$self
->{
$pname
} =
$newval
;
$self
->signal_emit(
'value-changed'
);
}
else
{
$self
->set_text(
$self
->_format_output(
$self
->get_value));
}
}
else
{
$self
->{
$pname
} =
$newval
;
}
}
sub
get_value {
my
$self
=
shift
;
$self
->get(
'value'
);
}
sub
set_value {
my
$self
=
shift
;
my
$new_value
=
shift
;
$self
->set(
'value'
,
$new_value
);
}
sub
set_now {
my
$self
=
shift
;
my
(
$hour
,
$minute
) = (
localtime
time
)[2,1];
my
$value
=
sprintf
'%02d:%02d'
,
$hour
,
$minute
;
$self
->set_value(
$value
);
}
sub
_do_value_changed {
my
$self
=
shift
;
my
$value
=
$self
->get_value;
$self
->set_text(
$self
->_format_output(
$self
->get_value));
}
sub
_do_focus_out_event {
my
$self
=
shift
;
$self
->set_value(
$self
->get_text);
return
FALSE;
}
sub
_do_key_press_event {
my
$self
=
shift
;
my
$key
=
shift
;
my
$key_val
=
$key
->keyval;
if
(
$key_val
== 65293) {
$self
->set_value(
$self
->get_text);
return
FALSE;
}
elsif
(
$key_val
>= 65361 &&
$key_val
<= 65364) {
$self
->set_value(
$self
->get_text);
return
$self
->_do_key_left
if
$key_val
== 65361;
return
$self
->_do_key_right
if
$key_val
== 65363;
return
$self
->_do_key_up
if
$key_val
== 65362;
return
$self
->_do_key_down
if
$key_val
== 65364;
}
else
{
return
FALSE;
}
}
sub
_do_key_left {
my
$self
=
shift
;
my
$selected
=
$self
->get_selected_component;
if
(!
$selected
) {
return
FALSE
if
$self
->get_position == 0;
$self
->_select_closest_component(
'left'
);
return
TRUE;
}
else
{
if
(
$selected
eq
'all'
) {
$self
->set_selected_component(
'meridiem'
)}
elsif
(
$selected
eq
'hours'
) {
return
FALSE; }
elsif
(
$selected
eq
'minutes'
) {
$self
->set_selected_component(
'hours'
) }
elsif
(
$selected
eq
'meridiem'
) {
$self
->set_selected_component(
'minutes'
) }
return
TRUE;
}
}
sub
_do_key_right {
my
$self
=
shift
;
my
$selected
=
$self
->get_selected_component;
$self
->_select_closest_component(
'right'
) and
return
TRUE
if
!
$selected
;
if
(!
$selected
) {
return
FALSE
if
$self
->get_position == 0;
$self
->_select_closest_component(
'left'
);
return
TRUE;
}
else
{
if
(
$selected
eq
'all'
) {
$self
->set_selected_component(
'hours'
) }
elsif
(
$selected
eq
'hours'
) {
$self
->set_selected_component(
'minutes'
) }
elsif
(
$selected
eq
'minutes'
) {
$self
->set_selected_component(
'meridiem'
) }
elsif
(
$selected
eq
'meridiem'
) {
return
FALSE; }
return
TRUE;
}
}
sub
_do_key_up {
my
$self
=
shift
;
my
$selected
=
$self
->get_selected_component;
$self
->_select_closest_component(
'up'
) and
return
TRUE
unless
$selected
;
my
(
$hours
,
$minutes
) =
split
/:/,
$self
->get_value;
if
(
$selected
eq
'hours'
) {
$hours
++;
}
elsif
(
$selected
eq
'minutes'
) {
$minutes
++;
}
elsif
(
$selected
eq
'meridiem'
) {
$hours
+=12;
}
elsif
(
$selected
eq
'all'
) {
$minutes
+=15;
}
my
$new_value
=
join
':'
,
$hours
,
$minutes
;
$self
->set_value(
$new_value
);
$self
->set_selected_component(
$selected
);
return
TRUE;
}
sub
_do_key_down {
my
$self
=
shift
;
my
$selected
=
$self
->get_selected_component;
$self
->_select_closest_component(
'down'
) and
return
TRUE
unless
$selected
;
my
(
$hours
,
$minutes
,
$seconds
) =
split
/:/,
$self
->get_value;
if
(
$selected
eq
'hours'
) {
$hours
--;
}
elsif
(
$selected
eq
'minutes'
) {
$minutes
--;
}
elsif
(
$selected
eq
'meridiem'
) {
$hours
-=12;
}
elsif
(
$selected
eq
'all'
) {
$minutes
-=15;
}
if
(
$minutes
< 0) {
my
$absolute_minutes
=
$minutes
* -1;
my
$delta_hours
=
int
(
$absolute_minutes
/ 60) + 1;
$hours
-=
$delta_hours
;
my
$delta_minutes
=
$absolute_minutes
% 60;
$minutes
= 60 -
$delta_minutes
;
}
if
(
$hours
< 0) {
my
$absolute_hours
=
$hours
* -1;
my
$delta_hours
=
$absolute_hours
% 24;
$hours
= 24 -
$delta_hours
;
}
my
$new_value
=
sprintf
'%02d:%02d'
,
$hours
,
$minutes
;
$self
->set_value(
$new_value
);
$self
->set_selected_component(
$selected
);
return
TRUE;
}
sub
_format_output {
my
$self
=
shift
;
my
$value
=
shift
;
carp
q[Usage is $self->_format_output($value) where ]
.
q[$value is a valid time in the format HH:MM:SS: ]
.
qq[you supplied ($value)]
unless
defined
$value
&&
$value
!~ /^\d\d:\d\d:\s\s$/;
return
''
if
$value
eq
''
;
my
(
$hours
,
$minutes
,
$seconds
) =
split
/:/,
$value
;
my
$ampm
;
if
(
$hours
== 0) {
$hours
= 12;
$ampm
=
'AM'
;
}
elsif
(
$hours
== 12) {
$ampm
=
'PM'
;
}
elsif
(
$hours
> 12) {
$hours
-= 12;
$ampm
=
'PM'
;
}
else
{
$ampm
=
'AM'
;
}
return
sprintf
qq[%02d:%02d $ampm]
,
$hours
,
$minutes
;
}
sub
get_selected_component {
my
$self
=
shift
;
my
(
$select_start
,
$select_end
) =
$self
->get_selection_bounds;
$select_start
= 0
unless
$select_start
;
$select_end
= 0
unless
$select_end
;
my
$selected
=
$select_end
-
$select_start
;
return
unless
$selected
== 2 || 8;
if
(
$select_start
== 0 &&
$select_end
== 2) {
return
'hours'
;
}
elsif
(
$select_start
== 3 &&
$select_end
== 5) {
return
'minutes'
;
}
elsif
(
$select_start
== 6 &&
$select_end
== 8) {
return
'meridiem'
;
}
elsif
(
$select_start
== 0 &&
$select_end
== 8) {
return
'all'
;
}
else
{
return
undef
;
}
}
sub
set_selected_component {
my
$self
=
shift
;
my
$field
=
shift
;
confess
q[Usage is $self->set_selected_component($field) where field is one of ]
.
q[hours, minutes, ampm, meridiem, all, or an empty string: ]
.
qq[you supplied($field)]
and
return
unless
$field
=~ /(hours|minutes|ampm|meridiem|all|none)/
||
$field
eq
''
;
if
(
$field
eq
'hours'
) {
$self
->select_region(0,2);
}
elsif
(
$field
eq
'minutes'
) {
$self
->select_region(3,5);
}
elsif
(
$field
=~ /ampm|meridiem/) {
$self
->select_region(6,8);
}
elsif
(
$field
eq
'all'
) {
$self
->select_region(0,8);
}
elsif
(
$field
eq
'none'
||
$field
eq
''
) {
$self
->select_region(0,0);
}
else
{
confess
qq[Invalid argument passed: $field]
;
}
}
sub
_select_closest_component {
my
$self
=
shift
;
my
$direction
=
shift
;
my
$cursor
=
$self
->get_position;
if
(
$cursor
== 0 ||
$cursor
== 1) {
$self
->set_selected_component(
'hours'
);
}
elsif
(
$cursor
== 2 &&
$direction
ne
'right'
) {
$self
->set_selected_component(
'hours'
);
}
elsif
(
$cursor
== 2 &&
$direction
eq
'right'
) {
$self
->set_selected_component(
'minutes'
);
}
elsif
(
$cursor
== 3 &&
$direction
eq
'left'
) {
$self
->set_selected_component(
'hours'
);
}
elsif
(
$cursor
== 3 &&
$direction
ne
'left'
) {
$self
->set_selected_component(
'minutes'
);
}
elsif
(
$cursor
== 4) {
$self
->set_selected_component(
'minutes'
);
}
elsif
(
$cursor
== 5 &&
$direction
ne
'right'
) {
$self
->set_selected_component(
'minutes'
);
}
elsif
(
$cursor
== 5 &&
$direction
eq
'right'
) {
$self
->set_selected_component(
'meridiem'
);
}
elsif
(
$cursor
== 6 &&
$direction
eq
'left'
) {
$self
->set_selected_component(
'minutes'
);
}
elsif
(
$cursor
== 6 &&
$direction
ne
'left'
) {
$self
->set_selected_component(
'meridiem'
);
}
elsif
(
$cursor
== 7 ||
$cursor
== 8) {
$self
->set_selected_component(
'meridiem'
);
}
return
TRUE;
}
sub
_parse_input {
my
$self
=
shift
;
my
$value
=
shift
||
''
;
$value
=~ s/^\s+//;
$value
=~ s/\s+$//;
return
''
unless
$value
;
my
(
$h
,
$m
,
$s
);
if
(
$value
=~ /^(\d{1,2})$/) {
$h
= $1;
$m
= 0;
$s
= 0;
}
elsif
(
$value
=~ /^([012]?[0-9]):?([0-5][0-9]):?([0-5][0-9])?$/) {
$h
= $1;
$m
= $2;
$s
= $3 || 0;
}
elsif
(
$value
=~ /^([012]?[0-9]):?([0-9][0-9])?\s*(am|pm)?$/i) {
$h
= $1;
$m
= $2 || 0;
$s
= 0;
$h
-= 12
if
$h
== 12 &&
lc
$3 eq
'am'
;
$h
+= 12
if
$h
<12 &&
lc
$3 eq
'pm'
;
}
elsif
(
$value
eq
''
) {
return
''
;
}
else
{
return
$self
->get_value;
}
if
(
$s
> 59) {
$m
++;
$s
=
$s
% 60;
}
if
(
$m
> 59) {
$h
++;
$m
=
$m
% 60;
}
if
(
$h
>= 24) {
$h
-=
int
(
$h
/ 24) * 24;
}
my
$parsed
=
sprintf
'%02d:%02d:%02d'
,
$h
,
$m
,
$s
;
return
$parsed
;
}
1;