#! perl

# this extension implements popup-menu functionality for urxvt. it works
# together with the urxvt::popup class - "no user serviceable parts inside".

sub refresh {
   my ($self) = @_;

   my $cmd = "\x1b[H";

   my $row = 1;
   for my $item (@{ $self->{data}{item} }) {
      my $rend = "normal";

      if ($row == $self->{hover}) {
         $rend = $self->{press} ? "active" : "hover";
      }

      $cmd .= "$item->{rend}{$rend}\x1b[K";
      $cmd .= $self->locale_encode ($item->{render}->($item));
      $cmd .= "\015\012";

      $row++;
   }

   $self->cmd_parse (substr $cmd, 0, -2);
}

sub on_motion_notify {
   my ($self, $event) = @_;

   delete $self->{hover};

   my ($row, $col) = ($event->{row}, $event->{col});
   if ($col >= 0 && $col < $self->ncol
       && $row >= 0 && $row < @{ $self->{data}{item} }) {
      $self->{hover} = $event->{row} + 1;
   }
   $self->refresh;

   1
}

sub on_button_press {
   my ($self, $event) = @_;

   $self->{press}[$event->{button}] = 1;
   $self->refresh;

   1
}

sub on_button_release {
   my ($self, $event) = @_;

   $self->{press}[$event->{button}] = 0;

   my ($row, $col) = ($event->{row}, $event->{col});
   if ($col >= 0 && $col < $self->ncol
       && $row >= 0 && $row < @{ $self->{data}{item} }) {
      my $item = $self->{data}{item}[$row];
      $item->{activate}->($event, $item);
   }

   $self->refresh;

   if ($event->{button} == $self->{data}{event}{button}) {
      $self->ungrab;
      $self->destroy;
   }

   1
}

sub on_focus_out {
   my ($self) = @_;

   delete $self->{hover};
   $self->refresh;

   ()
}

sub on_init {
   my ($self) = @_;

   my $data = $self->{data} = $urxvt::popup::self;

   $_->{width} = $self->strwidth ($_->{text})
      for @{ $data->{item} };

   $self->resource (title => "URxvt Popup Menu");
   $self->resource (name => "URxvt.popup");

   $self->resource ($_ => $data->{term}->resource ($_))
      for qw(font boldFont italicFont boldItalicFont color+0 color+1);

   my $width  = List::Util::max map $_->{width}, @{ $data->{item} };
   my $height = @{ $data->{item} };

   my $pos = "";

   if ($data->{event}) {
      my $x = int List::Util::max 0, $data->{event}{x_root} - $width * $data->{term}->fwidth  * 0.5;
      my $y = int List::Util::max 0, $data->{event}{y_root} -          $data->{term}->fheight * 0.5;
      $pos = "+$x+$y";
   }

   $self->resource (geometry => "${width}x${height}$pos");

   $self->{term}{urxvt_popup_init_done} = 1;

   ()
}

sub on_start {
   my ($self) = @_;

   $self->cmd_parse ("\x1b[?25l\x1b[?7l");
   $self->refresh;

   # might fail, but try anyways
   $self->grab ($self->{data}{event}{time}, 1)
      and $self->allow_events_async;

   on_button_press $self, $self->{data}{event} if $self->{data}{event}{button};

   ()
}

sub on_map_notify {
   my ($self, $event) = @_;

   # should definitely not fail
   $self->grab ($self->{data}{event}{time}, 1)
      and $self->allow_events_async;
}


