package SimpleGtk2;

use strict;
# Use the TRUE and FALSE constants exported by the Glib module.
use Glib qw(TRUE FALSE);
use Exporter;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
#use Data::Dumper;
#    print "-------------------------------\n";
#    print Dumper(\$attrlist);
    

$VERSION     = 1.00;
@ISA         = qw(Exporter);
@EXPORT      = ();
@EXPORT_OK   = qw(func1 func2);
#%EXPORT_TAGS = ( DEFAULT => [qw(&func1)],
#                 Both    => [qw(&func1 &func2)]);

# ---------------------------------------------------------------------

# widget object structure for window object list
sub new_widget {
    my %params = @_;
    my $self = { };
    $self->{type} = undef;
    $self->{name} = $params{'Name'} || undef;
    $self->{title} = $params{'Title'} || undef;
    $self->{pos_x} = $params{'Position'}[0] || undef;
    $self->{pos_y} = $params{'Position'}[1] || undef;
    $self->{width} = $params{'Size'}[0] || undef;
    $self->{height} = $params{'Size'}[1] || undef;
    $self->{obj_ref} = undef;
    return $self;
}

# ---------------------------------------------------------------------

# new Window (  Type => <type>              <= supported window types: toplevel, popup
#               Name => '<name>'            <= must be unique
#               Title => '<window title>
#               Width => width              <= otional
#               Height => height)           <= otional
sub new_window ($@) {
	my $class = shift;
	my %params = @_;
	my $window;
	my $self = {};
	$self->{objects} = {};
	$self->{groups} = {};
	$self->{type} = $params{'Type'};
	$self->{name} = $params{'Name'};
	$self->{title} = $params{'Title'};
	$self->{width} = $params{'Width'} || undef;
	$self->{height} = $params{'Height'} || undef;
	$self->{tooltips} = Gtk2::Tooltips->new();
	$self->{tooltips}->enable;
	bless $self, $class;
	
	# create the window
	$window = new Gtk2::Window($self->{type});
	$window->set_title($self->{title});
	$self->{window} = $window;
	
	# add signal handler
	$self->add_signal_handler($self->{name}, "destroy", sub {Gtk2->main_quit;});
	
	# add geometry if defined
	if ($self->{width} && $self->{height}) {
	    $window->set_default_size($self->{width}, $self->{height});
	}
	
	# Create the fixed container
    my $fixed = new Gtk2::Fixed();
    $self->{container} = $fixed;
    $self->{window}->add($fixed);	
	
	return $self;
}

# ---------------------------------------------------------------------

# display window with all widgets
sub show_all($) {
    my $self = shift;
    $self->{window}->show_all();
}

# ---------------------------------------------------------------------

# add signal to widget
# add_signal_handler(<name>, <signal>, <function>)
sub add_signal_handler($@) {
    my $self = shift;
	my ($name, $signal, $function) = @_;
    if ($name eq $self->{name}) {
        $self->{window}->signal_connect($signal, $function);
    } else {
        my $obj_ref = $self->get_widget($name);
        $obj_ref->signal_connect($signal, $function);
    }
}

# ---------------------------------------------------------------------

# get widget reference
# get_widget(<name>)    <= must be unique
sub get_widget($$) {
    my $self = shift;
    my $name = shift;
    return $self->{objects}->{$name}->{obj_ref};
}

# ---------------------------------------------------------------------

# get object hash from objects list
# get_object(<name>)    <= must be unique
sub get_object($$) {
    my $self = shift;
    my $name = shift;
    return $self->{objects}->{$name};
}

# ---------------------------------------------------------------------

# add_button(Name => <name>,                <= Name of the button. Must be unique
#            Position => [pos_x, pos_y], 
#            Title => <title>,
#            Size => [width, height],       <= Optional
#            Underlined => 0/1,             <= Optional
#            Tooltip => <tooltip-text>)     <= Optional
sub add_button($@) {
    my $self = shift;
    my %params = @_;
    my $object = new_widget(%params);
    $object->{type} = 'Button';
    
    # button specific fields
    $object->{underline} = $params{'Underline'} || 0;
    $object->{tooltip}   = $params{'Tooltip'} || undef;
    
    # create button
    my $button;
    # if underline in text should use
    if ($object->{underline}) {
        $button = Gtk2::Button->new_with_mnemonic($object->{title});
        $button->set_use_underline(TRUE);
    } else {
        $button = Gtk2::Button->new_with_label($object->{title});
    }
    
    # Check if tooltip should use
    $button->set_tooltip_text($object->{tooltip}) if defined $object->{tooltip};
    
    # size of the button
    if ($object->{width} && $object->{height}) {
        $button->set_size_request($object->{width}, $object->{height});
    }
    
    # positon of the button
    $self->{container}->put($button, $object->{pos_x}, $object->{pos_y});
    
    # add widget object to window objects list
    $object->{obj_ref} = $button;
    $self->{objects}->{$object->{name}} = $object;
}

# ---------------------------------------------------------------------

# add_check_button( Name => <name>,                <= Name of the button. Must be unique
#                   Position => [pos_x, pos_y], 
#                   Title => <title>,
#                   Underlined => 0/1,             <= Optional
#                   Tooltip => <tooltip-text>)     <= Optional
#                   )
sub add_check_button($@) {
    my $self = shift;
    my %params = @_;
    my $object = new_widget(%params);
    $object->{type} = 'CheckButton';
    
    # check button specific fields
    $object->{underline} = $params{'Underline'} || 0;
    $object->{tooltip}   = $params{'Tooltip'} || undef;
    
    # create check button
    my $check_button;
    # if underline in text should use
    if ($object->{underline}) {
        $check_button = Gtk2::CheckButton->new_with_mnemonic($object->{title});
        $check_button->set_use_underline(TRUE);
    } else {
        $check_button = Gtk2::CheckButton->new_with_label($object->{title});
    }
    
    # Check if tooltip should use
    if (defined($object->{tooltip})) {
        $self->{tooltips}->set_tip ($check_button, $object->{tooltip});
    }
    
    # positon of the button
    $self->{container}->put($check_button, $object->{pos_x}, $object->{pos_y});
    
    # add widget object to window objects list
    $object->{obj_ref} = $check_button;
    $self->{objects}->{$object->{name}} = $object;
}

# ---------------------------------------------------------------------

# add_radio_button( Name => <name>,                 <= Name of the button. Must be unique
#                   Position => [pos_x, pos_y], 
#                   Title => <title>,
#                   Group => <button_group>,        <= Name of the buttongroup. Must be unique
#                   Active => 0/1                   <= Which is the active button. Default is 0 (not active)
#                   Underlined => 0/1,              <= Optional
#                   Tooltip => <tooltip-text>)      <= Optional
#                   )
sub add_radio_button($@) {
    my $self = shift;
    my %params = @_;
    my $object = new_widget(%params);
    $object->{type} = 'RadioButton';
    
    # radio button specific fields
    $object->{group} = $params{'Group'} || undef;
    $object->{active} = $params{'Active'} || 0;
    $object->{underline} = $params{'Underline'} || 0;
    $object->{tooltip}   = $params{'Tooltip'} || undef;
    
    # create radio button
    my $radio_button;
    
    # get the group
    my $group = exists($self->{groups}->{$object->{group}}) ? $self->{groups}->{$object->{group}} : undef;
    # get the last widget from @group
    my $last = defined($group) ? @$group[-1] : undef;
    
    # if underline in text should use
    if ($object->{underline}) {
        $radio_button = Gtk2::RadioButton->new_with_label_from_widget ($last, $object->{title});
        $radio_button->set_use_underline(TRUE);
    } else {
        $radio_button = Gtk2::RadioButton->new_with_label($last, $object->{title});
    }

    # Check if tooltip should use
    if (defined($object->{tooltip})) {
        $self->{tooltips}->set_tip ($radio_button, $object->{tooltip});
    }
    
    # set radio button active
    $radio_button->set_active(TRUE) if $object->{active};
    
    # add group to window groups list
    unless (defined($group)) {
        $group = $radio_button->get_group();
        $self->{groups}->{$object->{group}} = $group;
    }
    
    # positon of the radio button
    $self->{container}->put($radio_button, $object->{pos_x}, $object->{pos_y});
    
    # add widget object to window objects list
    $object->{obj_ref} = $radio_button;
    $self->{objects}->{$object->{name}} = $object;
}




# ---------------------------------------------------------------------

# add_label (Name => <name>,                        <= name of the label. Must be unique
#            Title => <title>,
#            Position => [pos_x, pos_y], 
#            Underlined => 0/1,                     <= Optional
#            Widget => <name_of_linked_widget>      <= Optional in conjunction with underlined
#            Justify => <justify>                   <= Optional: left, right, center, fill
#            Wrapped => 0/1                         <= Optional. Only usable in a frame
sub add_label($@) {
    my $self = shift;
    my %params = @_;
    my $object = new_widget(%params);
    $object->{type} = 'Label';
    
    # label specific fields
    $object->{underline} = $params{'Underline'} || 0;
    $object->{widget} = $params{'Widget'} || undef;
    $object->{justify} = $params{'Justify'} || undef;
    $object->{wrapped} = $params{'Wrapped'} || 0;

    # create label
    my $label;
    if ($object->{underline}) {
        $label = Gtk2::Label->new_with_mnemonic($object->{title});
        my $obj_ref = $self->get_widget($object->{widget});
        $label->set_mnemonic_widget($obj_ref);
    } else {
        $label = Gtk2::Label->new($object->{title});
    }
    
    # if text should wrapped
    $label->set_line_wrap($object->{wrapped});
    
    # should text justified
    $label->set_justify($object->{justify}) if defined;
    
    # set positon of the label
    $self->{container}->put($label, $object->{pos_x}, $object->{pos_y});
    
    # add widget object to window objects hash
    $object->{obj_ref} = $label;
    $self->{objects}->{$object->{name}} = $object;
}

# ---------------------------------------------------------------------

# add_frame (   Name => <name>,                 <= widget name - must be unique
#               Title => <title>,
#               Position => [pos_x, pos_y], 
#               Size => [width, height],
#               )
sub add_frame($@) {
    my $self = shift;
    my %params = @_;
    my $object = new_widget(%params);
    $object->{type} = 'Frame';
    
    # create frame
    my $frame;
    if ($object->{title}) {
        $frame = Gtk2::Frame->new($object->{title});
    } else {
        $frame = Gtk2::Frame->new();        
    }
    
    $frame->set_size_request($object->{width}, $object->{height});

    # set positon of the frame
    $self->{container}->put($frame, $object->{pos_x}, $object->{pos_y});
    
    # add widget object to window objects hash
    $object->{obj_ref} = $frame;
    $self->{objects}->{$object->{name}} = $object;
    
}
# ---------------------------------------------------------------------

# add text entry field
# add_entry (   Name => <name>,                 <= object name - must be unique
#               Title => <title>,
#               Position => [pos_x, pos_y], 
#               Size => [width, height],
#               Align => <xalign>               <= Optional: left (default), right
#               Tooltip => <tooltip-text>)      <= Optional
#               )
sub add_entry($@) {
    my $self = shift;
    my %params = @_;
    my $object = new_widget(%params);
    $object->{type} = 'Entry';
    
    # entry specific fields
    $object->{tooltip} = $params{'Tooltip'} || undef;
    $object->{align} = $params{'Align'} || 0;
    
    # create entry
    my $entry = Gtk2::Entry->new();
    if ($object->{title}) {
        $entry->set_text($object->{title});
    }
    
    # check if alignment for text is set
    if ($object->{align} eq 'right') {
        $entry->set_alignment(1);
    }
    
    # check if different size is requested
    if ($object->{width} && $object->{height}) {
        $entry->set_size_request($object->{width}, $object->{height});
    }

    # Check if tooltip should use
    if (defined($object->{tooltip})) {
        #my $tooltip = Gtk2::Tooltips->new();
        $self->{tooltips}->set_tip ($entry, $object->{tooltip});
    }
    
    # set positon of the entry
    $self->{container}->put($entry, $object->{pos_x}, $object->{pos_y});
    
    # add widget object to window objects hash
    $object->{obj_ref} = $entry;
    $self->{objects}->{$object->{name}} = $object;
}

# ---------------------------------------------------------------------

# add_spin_button(  Name => <name>,                 <= widget name - must be unique
#                   Position => [pos_x, pos_y], 
#                   Size => [width, height],        <= Optional
#                   Start => <start_value>,
#                   Min => <min_value>,
#                   Max => <max_value>,
#                   Step => <step_in/decrease>
#                   Align => <align>                <= Optional (left, right)
#                   Climbrate => <from 0.0 to 1.0>  <= Optional (default: 0.0)
#                   Digits => <used_digits>         <= Optional (default: 0)
#                   Tooltip => <tooltip-text>)      <= Optional
#                   )
sub add_spin_button($@) {
    my $self = shift;
    my %params = @_;
    my $object = new_widget(%params);
    $object->{type} = 'SpinButton';

    # spin button specific fields
    $object->{start} = $params{'Start'} || 0;
    $object->{min} = $params{'Min'} || 0;
    $object->{max} = $params{'Max'} || 0;
    $object->{step} = $params{'Step'} || 0;
    $object->{align} = $params{'Align'} || 0;
    $object->{climbrate} = $params{'Climbrate'} || 0.0;
    $object->{digits} = $params{'Digits'} || 0;
    $object->{tooltip} = $params{'Tooltip'} || undef;

    # first create an adjustment widget to hold information about the range of 
    # values that the spin button can take
    my $adjustment = Gtk2::Adjustment->new( $object->{start},
                                            $object->{min},
				                            $object->{max},
				                            $object->{step},
				                            0,
				                            0);
    
    # now the spin button follows
    my $spin = Gtk2::SpinButton->new ($adjustment, $object->{climbrate}, $object->{digits});
    
    # spin button can contain only a numeric value
    $spin->set_numeric(TRUE);
    
    # set the spin button to wrap around between the upper and lower range values
    $spin->set_wrap(TRUE);
    
    # The update policy of the spin button
    $spin->set_update_policy ('if-valid');
    
    # Check if tooltip should use
#    if (defined($object->{tooltip})) {
#        #my $tooltip = Gtk2::Tooltips->new();
#        $self->{tooltips}->set_tip ($spin, $object->{tooltip});
#    }

    # check if spin button should have a different size
    if ($object->{width} && $object->{height}) {
        $spin->set_size_request($object->{width}, $object->{height});
    }

    if ($object->{align} eq 'right') {
        $spin->set_alignment(1);
    }

    # set positon of the entry
    $self->{container}->put($spin, $object->{pos_x}, $object->{pos_y});
    
    # add widget object to window objects hash
    $object->{obj_ref} = $spin;
    $self->{objects}->{$object->{name}} = $object;
}

# ---------------------------------------------------------------------

# add_combo_box(    Name => <name>,                     <= widget name - must be unique
#                   Position => [pos_x, pos_y], 
#                   Size => [width, height],            <= Optional
#                   Data => [Array_of_values>],
#                   Start => <start_value>,
#                   Columns = <wrap_list_to_x_columns>  <= Optional
#                   Align => <align>                    <= Optional (left, right)
#                   Tooltip => <tooltip-text>)          <= Optional
#)
sub add_combo_box($@) {
    my $self = shift;
    my %params = @_;
    my $object = new_widget(%params);
    $object->{type} = 'ComboBox';

    # combo box specific fields
    $object->{data} = $params{'Data'} || [];
    $object->{start} = $params{'Start'}-1 || 0;
    $object->{columns} = $params{'Columns'} || undef;
    $object->{align} = $params{'Align'} || 0;
    $object->{tooltip} = $params{'Tooltip'} || undef;

    # create Gtk2::TreeModel object
    my $model = Gtk2::ListStore->new(qw/Glib::String/);
    
    # add data to ListStore object
    foreach(@{$object->{data}}) {
        my $iter = $model->append;
        $model->set($iter,0 => $_);
    }   
    
    # create combo box
    my $combobox = Gtk2::ComboBox->new_text();
    $combobox->set_model($model);
    
    # set active item
    $combobox->set_active($object->{start});
    
    # check if list should wrap into x columns
    $combobox->set_wrap_width($object->{columns}) if defined($object->{columns});
    
    # check if different size is requested
    if ($object->{width} && $object->{height}) {
        $combobox->set_size_request($object->{width}, $object->{height});
    }

    # Check if tooltip should use
    if (defined($object->{tooltip})) {
        $self->{tooltips}->set_tip ($combobox, $object->{tooltip});
    }
    
    # set positon of the entry
    $self->{container}->put($combobox, $object->{pos_x}, $object->{pos_y});
    
    # add widget object to window objects hash
    $object->{obj_ref} = $combobox;
    $self->{objects}->{$object->{name}} = $object;
}

# ---------------------------------------------------------------------








# ---------------------------------------------------------------------

# change font attributes of an widget
# change_font(  Name => <name>,                 <= widget name - must be unique
#               Font => <font>                  <= Arial, Sans, ...
#               Size => <size>                  <= integer
#               Weight => <weight>              <= ultralight, light, normal, semibold, bold, ultrabold, heavy
#               Style => <style>)               <= normal, oblique, italic
# TODO: should use modify_<something>? instead of set_sttributes
sub change_font($@) {
    my $self = shift;
    my %params = @_;
    my $attrlist = Gtk2::Pango::AttrList->new();
    
    # change attributes
    if (defined ($params{'Font'})) {
        my $new_font = Gtk2::Pango::AttrFamily->new($params{'Font'});
        $attrlist->change ($new_font);        
    }
    if (defined ($params{'Size'})) {
        my $new_size = Gtk2::Pango::AttrSize->new($params{'Size'});
        $attrlist->change ($new_size);        
    }
    if (defined ($params{'Weight'})) {
        my $new_weight = Gtk2::Pango::AttrWeight->new($params{'Weight'});
        $attrlist->change ($new_weight);        
    }
    if (defined ($params{'Style'})) {
        my $new_style = Gtk2::Pango::AttrStyle->new($params{'Style'});
        $attrlist->change ($new_style);        
    }
    
    # get object
    my $object = $self->get_object($params{'Name'});

    # change attributes of text
    if ($object->{type} =~ m/Label/) {
        $object->{obj_ref}->set_attributes($attrlist);
    } else {
        $object->{obj_ref}->child->set_attributes($attrlist);
    }
    
}

# ---------------------------------------------------------------------




# ---------------------------------------------------------------------

# change_bg(    Name => <name>,                     <= widget name - must be unique
#               Background => <background_color>)   <= color as name or value
# TODO: Does only set text background
sub change_bg($@) {
    my $self = shift;
    my %params = @_;
    my $attrlist = Gtk2::Pango::AttrList->new();
    
    # get object
    my $object = $self->get_object($params{'Name'});
    
    # change attributes of text
    if ($object->{type} eq 'Label') {
        $object->{obj_ref}->set_markup("<span background=\"$params{'Background'}\"><b>$object->{title}</b></span>");
    } else {
        $object->{obj_ref}->child->set_markup("<span background=\"$params{'Background'}\"><b>$object->{title}</b></span>");
    }
}

# ---------------------------------------------------------------------

# change_fg(    Name => <name>,                 <= widget name - must be unique
#               Foreground => <foreground_color>)               <= color as name or value
# TODO: Does only set text background
sub change_fg($@) {
    my $self = shift;
    my %params = @_;
    my $attrlist = Gtk2::Pango::AttrList->new();
    
    # get object
    my $object = $self->get_object($params{'Name'});
    
    # change attributes of text
    if ($object->{type} eq 'Label') {
        $object->{obj_ref}->set_markup("<span foreground=\"$params{'Foreground'}\"><b>$object->{title}</b></span>");
    } else {
        $object->{obj_ref}->child->set_markup("<span foreground=\"$params{'Foreground'}\"><b>$object->{title}</b></span>");
    }
}

    



1;
