The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Padre::Wx::Panel::FindFast;

use 5.008;
use strict;
use warnings;
use Padre::Search            ();
use Padre::Wx::FBP::FindFast ();
use Padre::Logger;

our $VERSION = '1.00';
our @ISA     = 'Padre::Wx::FBP::FindFast';





######################################################################
# Constructor

sub new {
	my $class = shift;
	my $self  = $class->SUPER::new(@_);

	# Immediately hide the panel to prevent display glitching
	$self->Hide;

	# Create a private pane in AUI
	$self->main->aui->AddPane(
		$self,
		Padre::Wx->aui_pane_info(
			Name           => 'footer',
			PaneBorder     => 0,
			Resizable      => 1,
			CaptionVisible => 0,
			Layer          => 1,
			PaneBorder     => 0,
			)->Bottom->Hide,
	);

	return $self;
}





######################################################################
# Event Handlers

sub on_char {
	my $self  = shift;
	my $event = shift;

	unless ( $event->HasModifiers ) {
		my $key = $event->GetKeyCode;

		# Advance to the next match on enter
		if ( $key == Wx::K_RETURN ) {
			TRACE('on_char (return)') if DEBUG;
			if ( $self->{find_next}->IsEnabled ) {
				$self->search_next;
			}
			return $event->Skip(0);
		}

		# Return to the editor on escape
		if ( $key == Wx::K_ESCAPE ) {
			TRACE('on_char (escape)') if DEBUG;
			$self->cancel;
			return $event->Skip(0);
		}
	}

	$event->Skip(1);
}

sub on_text {
	TRACE('on_text') if DEBUG;
	my $self   = shift;
	my $editor = $self->current->editor or return;
	my $lock   = $self->lock_update;

	# Do we have a search
	if ( $self->refresh ) {

		# Reset the background colour
		$self->{find_term}->SetBackgroundColour( $self->base_colour );
	} else {

		# Clear any existing select to prevent
		# showing a stale match result.
		my $position = $editor->GetCurrentPos;
		my $anchor   = $editor->GetAnchor;
		unless ( $position == $anchor ) {
			$editor->SetAnchor($position);
		}

		return;
	}

	# Restart the search for each change
	unless ( $self->{find_term}->GetValue eq $editor->GetSelectedText ) {
		$editor->SetSelection( 0, 0 );
	}

	# Run the search
	unless ( $self->main->search_next( $self->as_search ) ) {
		$self->{find_term}->SetBackgroundColour( $self->bad_colour );
	}

	return;
}

sub on_kill_focus {
	my $self = shift;
	$self->hide;
}

sub cancel {
	TRACE('cancel') if DEBUG;
	my $self = shift;

	# Go back to where we were before if there is no match on close
	$self->restore;
	delete $self->{before};

	# Shift focus to the editor
	$self->main->editor_focus;
	$self->hide;
}

sub restore {
	TRACE('restore') if DEBUG;
	my $self   = shift;
	my $before = $self->{before} or return;
	my $editor = $self->current->editor or return;
	$editor->GetCurrentPos == $editor->GetAnchor or return;
	$editor->GetLineCount == $before->{lines} or return;

	# Set the selection
	my $lock = $editor->lock_update;
	$editor->SetCurrentPos( $before->{pos} );
	$editor->SetAnchor( $before->{anchor} );

	# Scroll to get the selection to the original position
	unless ( $editor->GetFirstDocumentLine == $before->{first} ) {
		$editor->ScrollToLine( $before->{first} );
	}

	return 1;
}

# Start a fresh search with some text
sub search_start {
	TRACE('search_start') if DEBUG;
	my $self = shift;
	my $text = shift;
	my $lock = $self->lock_update;
	$self->{find_term}->SetValue($text);
	$self->{find_term}->SelectAll;
	return;
}

# Advance the search to the next match
sub search_next {
	TRACE('search_next') if DEBUG;
	my $self   = shift;
	my $search = $self->as_search or return;
	my $editor = $self->current->editor or return;
	$self->main->search_next($search);
}

# Advance the search to the previous match
sub search_previous {
	TRACE('search_previous') if DEBUG;
	my $self   = shift;
	my $search = $self->as_search or return;
	my $editor = $self->current->editor or return;
	$self->main->search_previous($search);
}





######################################################################
# Main Methods

sub show {
	my $self = shift;
	my $editor = $self->current->editor or return;

	# Capture the selection location before we opened the panel
	$self->{before} = {
		lines  => $editor->GetLineCount,
		pos    => $editor->GetCurrentPos,
		anchor => $editor->GetAnchor,
		first  => $editor->GetFirstDocumentLine,
	};

	# Reset the panel
	$self->{find_term}->ChangeValue('');
	$self->{find_term}->SetBackgroundColour( $self->base_colour );
	$self->{find_term}->SetFocus;
	$self->refresh;

	# Show the AUI pane
	my $aui = $self->main->aui;
	$aui->GetPane('footer')->Show;
	$aui->Update;
}

sub hide {
	my $self = shift;
	my $aui  = $self->main->aui;

	# Hide the AUI pane
	$aui->GetPane('footer')->Hide;
	$aui->Update;
}

sub refresh {
	my $self = shift;
	my $show = $self->as_search ? 1 : 0;
	$self->{find_next}->Enable($show);
	$self->{find_previous}->Enable($show);
	return $show;
}





######################################################################
# Support Methods

sub as_search {
	my $self = shift;
	Padre::Search->new(
		find_term => $self->{find_term}->GetValue,
		find_case => 0,
	);
}

sub lock_update {
	my $self   = shift;
	my $lock   = Wx::WindowUpdateLocker->new( $self->{find_term} );
	my $editor = $self->current->editor;
	if ($editor) {
		$lock = [ $lock, $editor->lock_update ];
	}
	return $lock;
}

sub base_colour {
	Wx::SystemSettings::GetColour(Wx::SYS_COLOUR_WINDOW);
}

sub bad_colour {
	my $self = shift;
	my $base = $self->base_colour;
	return Wx::Colour->new(
		$base->Red,
		int( $base->Green * 0.5 ),
		int( $base->Blue * 0.5 ),
	);
}

1;

# Copyright 2008-2013 The Padre development team as listed in Padre.pm.
# LICENSE
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl 5 itself.