summaryrefslogtreecommitdiffstats
path: root/src/perl/urxvt-popup
diff options
context:
space:
mode:
Diffstat (limited to 'src/perl/urxvt-popup')
-rw-r--r--src/perl/urxvt-popup139
1 files changed, 139 insertions, 0 deletions
diff --git a/src/perl/urxvt-popup b/src/perl/urxvt-popup
new file mode 100644
index 0000000..c1e5ac0
--- /dev/null
+++ b/src/perl/urxvt-popup
@@ -0,0 +1,139 @@
+#! 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;
+}
+
+