package install::gtk; # $Id$
use diagnostics;
use strict;
use ugtk2;
use mygtk2;
use common;
use lang;
use devices;
#-#####################################################################################
#-INTERN CONSTANT
#-#####################################################################################
#- if we're running for the doc team, we want screenshots with
#- a good B&W contrast: we'll override values of our theme
my $theme_overriding_for_doc = q(style "galaxy-default"
{
base[SELECTED] = "#E0E0FF"
base[ACTIVE] = "#E0E0FF"
base[PRELIGHT] = "#E0E0FF"
bg[SELECTED] = "#E0E0FF"
bg[ACTIVE] = "#E0E0FF"
bg[PRELIGHT] = "#E0E0FF"
text[ACTIVE] = "#000000"
text[PRELIGHT] = "#000000"
text[SELECTED] = "#000000"
fg[SELECTED] = "#000000"
}
style "white-on-blue"
{
base[NORMAL] = { 0.93, 0.93, 0.93 }
bg[NORMAL] = { 0.93, 0.93, 0.93 }
text[NORMAL] = "#000000"
fg[NORMAL] = "#000000"
}
style "background"
{
bg[NORMAL] = { 0.93, 0.93, 0.93 }
}
style "background-logo"
{
bg[NORMAL] = { 0.70, 0.70, 0.70 }
}
widget "*logo*" style "background-logo"
);
#------------------------------------------------------------------------------
sub load_rc {
my ($o, $name) = @_;
my $f = $name;
-r $name or $f = find { -r $_ } map { "$_/themes-$name.rc" } ("share", $ENV{SHARE_PATH}, dirname(__FILE__) . '/..');
if ($f) {
Gtk2::Rc->parse_string($o->{doc} ? $theme_overriding_for_doc : scalar cat_($f));
}
}
#------------------------------------------------------------------------------
sub load_font {
my ($o) = @_;
if (lang::text_direction_rtl()) {
Gtk2::Widget->set_default_direction('rtl');
my ($x, $y) = $::WizardWindow->get_position;
my ($width) = $::WizardWindow->get_size;
$::WizardWindow->move($::rootwidth - $width - $x, $y);
}
Gtk2::Rc->parse_string(q(
style "default-font"
{
font_name = ") . lang::l2pango_font($o->{locale}{lang}) . q("
}
widget "*" style "default-font"
));
}
#------------------------------------------------------------------------------
sub default_theme {
my ($o) = @_;
$o->{simple_themes} || $o->{vga16} ? 'blue' : 'galaxy';
}
sub install_theme {
my ($o) = @_;
load_rc($o, $o->{theme} ||= default_theme($o));
load_font($o);
my $win = gtknew('Window', widget_name => 'background');
$win->realize;
mygtk2::set_root_window_background_with_gc($win->style->bg_gc('normal'));
}
#------------------------------------------------------------------------------
my %steps;
sub create_steps_window {
my ($o) = @_;
return if $::stepswidth == 0;
$o->{steps_window} and $o->{steps_window}->destroy;
$steps{$_} ||= gtknew('Pixbuf', file => "steps_$_") foreach qw(on off done);
my $category = sub {
gtknew('HBox', children_tight => [
gtknew('Label', text_markup => '' . $_[0] . '', widget_name => 'Step-categories')
]);
};
my @l = $category->(N("Installation"));
foreach (grep { !eval $o->{steps}{$_}{hidden} } @{$o->{orderedSteps}}) {
if ($_ eq 'setRootPassword_addUser') {
push @l, '', $category->(N("Configuration"));
}
my $img = gtknew('Image', file => 'steps_off.png');
$steps{steps}{$_}{img} = $img;
$steps{steps}{$_}{raw_text} = translate($o->{steps}{$_}{text});
push @l, gtknew('HBox', spacing => 7, children_tight => [ '', '', $img, $steps{steps}{$_}{text} = gtknew('Label', text => $steps{steps}{$_}{raw_text}) ]);
}
my $offset = 20;
$o->{steps_window} =
gtknew('Window', width => ($::stepswidth - $offset), widget_name => 'Steps',
position => [ lang::text_direction_rtl() ? $::rootwidth - $::stepswidth : $offset, 150 ],
child => gtknew('VBox', spacing => 6, children_tight => \@l));
$o->{steps_window}->show;
}
sub update_steps_position {
my ($o) = @_;
return if !$steps{steps};
my $last_step;
foreach (@{$o->{orderedSteps}}) {
exists $steps{steps}{$_} or next;
if ($o->{steps}{$_}{entered} && !$o->{steps}{$_}{done}) {
$steps{steps}{$_}{img}->set_from_pixbuf($steps{on});
$steps{steps}{$_}{text}->set_markup('' . $steps{steps}{$_}{raw_text} . '');
if ($last_step) {
$steps{steps}{$last_step}{img}->set_from_pixbuf($steps{done});
$steps{steps}{$last_step}{text}->set_markup('' . $steps{steps}{$last_step}{raw_text} . '');
}
return;
}
$last_step = $_;
}
mygtk2::flush(); #- for auto_installs which never go through the Gtk2 main loop
}
#------------------------------------------------------------------------------
sub create_logo_window {
my ($o) = @_;
return if $::logowidth == 0;
mygtk2::may_destroy($o->{logo_window});
my $file = "logo-mandriva.png";
$o->{logo_window} =
gtknew('Window',
width => $::logowidth, height => $::logoheight,
widget_name => 'logo',
child => gtknew('Image', file => $file),
);
$o->{logo_window}->show;
}
#------------------------------------------------------------------------------
sub init_gtk {
my ($o) = @_;
symlink("/tmp/stage2/etc/$_", "/etc/$_") foreach qw(gtk-2.0 pango fonts);
if ($o->{vga16}) {
#- inactivate antialias in VGA16 because it makes fonts look worse
output('/tmp/fonts.conf',
q(
package ugtk;
use diagnostics;
use strict;
use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK $border);
@ISA = qw(Exporter);
%EXPORT_TAGS = (
helpers => [ qw(create_okcancel createScrolledWindow create_menu create_notebook create_packtable create_hbox create_vbox create_adjustment create_box_with_title create_treeitem) ],
wrappers => [ qw(gtksignal_connect gtkradio gtkpack gtkpack_ gtkpack__ gtkpack2 gtkpack3 gtkpack2_ gtkpack2__ gtkpowerpack gtkcombo_setpopdown_strings gtkset_editable gtksetstyle gtkset_text gtkset_tip gtkappenditems gtkappend gtkset_shadow_type gtkset_layout gtkset_relief gtkadd gtkput gtktext_insert gtkset_usize gtksize gtkset_justify gtkset_active gtkset_sensitive gtkset_modal gtkset_border_width gtkmove gtkresize gtkshow gtkhide gtkdestroy gtkflush gtkcolor gtkset_mousecursor gtkset_mousecursor_normal gtkset_mousecursor_wait gtkset_background gtkset_default_fontset gtkctree_children gtkxpm gtkpng create_pix_text get_text_coord fill_tiled gtkicons_labels_widget write_on_pixmap gtkcreate_xpm gtkcreate_png gtkbuttonset gtkroot gtkentry) ],
various => [ qw(add2notebook add_icon_path n_line_size) ],
);
$EXPORT_TAGS{all} = [ map { @$_ } values %EXPORT_TAGS ];
@EXPORT_OK = map { @$_ } values %EXPORT_TAGS;
my $use_pixbuf;
my $use_imlib;
my $use_gnome;
BEGIN {
eval { require Gtk::Gdk::Pixbuf; Gtk::Gdk::Pixbuf->init };
$use_pixbuf = $@ ? 0 : 1;
eval { require Gtk::Gdk::ImlibImage; Gtk::Gdk::ImlibImage->init };
$use_imlib = $@ ? 0 : 1;
eval { require Gnome };
$use_gnome = $@ ? 0 : 1;
}
use Gtk;
use c;
use log;
use common;
my @icon_paths;
sub add_icon_path { push @icon_paths, @_ }
sub icon_paths {
(@icon_paths, $ENV{SHARE_PATH}, "$ENV{SHARE_PATH}/icons", "$ENV{SHARE_PATH}/libDrakX/pixmaps", "/usr/lib/libDrakX/icons", "pixmaps", 'standalone/icons');
}
#-#######################
# gtk widgets wrappers
#-#######################
sub gtkdestroy { $_[0] and $_[0]->destroy }
sub gtkflush { Gtk->main_iteration while Gtk->events_pending }
sub gtkhide { $_[0]->hide; $_[0] }
sub gtkmove { $_[0]->window->move($_[1], $_[2]); $_[0] }
sub gtkpack { gtkpowerpack(1, 1, @_) }
sub gtkpack_ { gtkpowerpack('arg', 1, @_) }
sub gtkpack__ { gtkpowerpack(0, 1, @_) }
sub gtkpack2 { gtkpowerpack(1, 0, @_) }
sub gtkpack2_ { gtkpowerpack('arg', 0, @_) }
sub gtkpack2__ { gtkpowerpack(0, 0, @_) }
sub gtkpack3 { gtkpowerpack($a?1:0, 0, @_) }
sub gtkput { $_[0]->put(gtkshow($_[1]), $_[2], $_[3]); $_[0] }
sub gtkpixmap { new Gtk::Pixmap(gdkpixmap(@_)) }
sub gtkresize { $_[0]->window->resize($_[1], $_[2]); $_[0] }
sub gtkset_active { $_[0]->set_active($_[1]); $_[0] }
sub gtkset_border_width { $_[0]->set_border_width($_[1]); $_[0] }
sub gtkset_editable { $_[0]->set_editable($_[1]); $_[0] }
sub gtkset_justify { $_[0]->set_justify($_[1]); $_[0] }
sub gtkset_layout { $_[0]->set_layout($_[1]); $_[0] }
sub gtkset_modal { $_[0]->set_modal($_[1]); $_[0] }
sub gtkset_mousecursor_normal { gtkset_mousecursor(68, @_) }
sub gtkset_mousecursor_wait { gtkset_mousecursor(150, @_) }
sub gtkset_relief { $_[0]->set_relief($_[1]); $_[0] }
sub gtkset_sensitive { $_[0]->set_sensitive($_[1]); $_[0] }
sub gtkset_tip { $_[0]->set_tip($_[1], $_[2]) if $_[2]; $_[1] }
sub gtkset_shadow_type { $_[0]->set_shadow_type($_[1]); $_[0] }
sub gtkset_style { $_[0]->set_style($_[1]); $_[0] }
sub gtkset_usize { $_[0]->set_usize($_[1],$_[2]); $_[0] }
sub gtkshow { $_[0]->show; $_[0] }
sub gtksize { $_[0]->size($_[1],$_[2]); $_[0] }
sub gdkpixmap {
my ($f, $w) = @_;
$f =~ m|.png$| and return gtkcreate_png($f);
$f =~ m|.xpm$| and return gtkcreate_xpm($w, $f);
}
sub gtkadd {
my $w = shift;
foreach (@_) {
ref $_ or $_ = new Gtk::Label($_);
$w->add($_);
$_->show;
}
$w
}
sub gtkappend {
my $w = shift;
foreach (@_) {
my $l = $_;
ref $l or $l = new Gtk::Label($l);
$w->append($l);
$l->show;
}
$w
}
sub gtkappenditems {
my $w = shift;
$_->show() foreach @_;
$w->append_items(@_);
$w
}
sub gtkbuttonset {
gtkdestroy($_[0]->child);
gtkadd($_[0], gtkshow($_[1]))
}
sub gtkentry {
my ($text) = @_;
my $e = new Gtk::Entry;
$e->set_text($text);
$e;
}
sub gtksetstyle {
my ($w, $s) = @_;
$w->set_style($s);
$w;
}
sub gtkcolor {
my ($r, $g, $b) = @_;
my $color = bless { red => $r, green => $g, blue => $b }, 'Gtk::Gdk::Color';
gtkroot()->get_colormap->color_alloc($color);
}
sub gtkradio {
my $def = shift;
my $radio;
map { $radio = new Gtk::RadioButton($_, $radio ? $radio : ());
$radio->set_active($_ eq $def); $radio } @_;
}
sub gtkroot {
Gtk->init;
Gtk->set_locale;
Gtk::Gdk::Window->new_foreign(Gtk::Gdk->ROOT_WINDOW);
}
sub gtkset_background {
my ($r, $g, $b) = @_;
my $root = gtkroot();
my $gc = Gtk::Gdk::GC->new($root);
my $color = gtkcolor($r, $g, $b);
$gc->set_foreground($color);
$root->set_background($color);
my ($h, $w) = $root->get_size;
$root->draw_rectangle($gc, 1, 0, 0, $w, $h);
}
sub gtktext_insert {
my ($w, $t) = @_;
$w->freeze;
$w->backward_delete($w->get_length);
$w->insert(undef, undef, undef, $t);
#- DEPRECATED? needs \n otherwise in case of one line text the beginning is not shown (even with the vadj->set_value)
$w->set_word_wrap(1);
#- $w->vadj->set_value(0);
$w->thaw;
$w;
}
sub gtkset_text {
my ($w, $s) = @_;
$w->set_text($s);
$w;
}
sub gtkcombo_setpopdown_strings {
my $w = shift;
$w->set_popdown_strings(@_);
$w;
}
sub gtkappend_text {
my ($w, $s) = @_;
$w->append_text($s);
$w;
}
sub gtkprepend_text {
my ($w, $s) = @_;
$w->prepend_text($s);
$w;
}
sub gtkset_mousecursor {
my ($type, $w) = @_;
($w || gtkroot())->set_cursor(Gtk::Gdk::Cursor->new($type));
}
sub gtksignal_connect {
my $w = shift;
$w->signal_connect(@_);
$w;
}
#-#######################
# create widgets wrappers
#-#######################
sub create_adjustment {
my ($val, $min, $max) = @_;
new Gtk::Adjustment($val, $min, $max + 1, 1, ($max - $min + 1) / 10, 1);
}
sub create_box_with_title {
my $o = shift;
my $nbline = sum(map { round(length($_) / 60 + 1/2) } map { split "\n" } @_);
my $box = new Gtk::VBox(0,0);
return $box if $nbline == 0;
$o->{box_size} = n_line_size($nbline, 'text', $box);
if (@_ <= 2 && $nbline > 4) {
$o->{icon} && !$::isWizard and
eval { gtkpack__($box, gtkset_border_width(gtkpack_(new Gtk::HBox(0,0), 1, gtkpng($o->{icon})),5)) };
my $wanted = $o->{box_size};
$o->{box_size} = min(200, $o->{box_size});
my $has_scroll = $o->{box_size} < $wanted;
my $wtext = new Gtk::Text;
$wtext->can_focus($has_scroll);
chomp(my $text = join("\n", @_));
my $scroll = createScrolledWindow(gtktext_insert($wtext, $text));
$scroll->set_usize(400, $o->{box_size});
gtkpack__($box, $scroll);
} else {
my $a = !$::no_separator;
undef $::no_separator;
if ($o->{icon} && !$::isWizard) {
gtkpack__($box,
gtkpack_(new Gtk::HBox(0,0),
0, gtkset_usize(new Gtk::VBox(0,0), 15, 0),
0, eval { gtkpng($o->{icon}) },
0, gtkset_usize(new Gtk::VBox(0,0), 15, 0),
1, gtkpack_($o->{box_title} = new Gtk::VBox(0,0),
1, new Gtk::HBox(0,0),
(map {
my $w = ref $_ ? $_ : new Gtk::Label($_);
$::isWizard and $w->set_justify("left");
$w->set_name("Title");
(0, $w);
} map { ref $_ ? $_ : warp_text($_) } @_),
1, new Gtk::HBox(0,0),
)
),
if_($a, new Gtk::HSeparator)
)
} else {
gtkpack__($box,
(map {
my $w = ref $_ ? $_ : new Gtk::Label($_);
$::isWizard and $w->set_justify("left");
$w->set_name("Title");
$w;
} map { ref $_ ? $_ : warp_text($_) } @_),
if_($a, new Gtk::HSeparator)
)
}
}
}
sub create_hbox { gtkset_layout(gtkset_border_width(new Gtk::HButtonBox, 3), $_[0] || 'spread') }
sub create_menu {
my $title = shift;
my $w = new Gtk::MenuItem($title);
$w->set_submenu(gtkshow(gtkappend(new Gtk::Menu, @_)));
$w
}
sub create_notebook {
my $n = new Gtk::Notebook;
add2notebook($n, splice(@_, 0, 2)) while @_;
$n
}
sub create_packtable {
my ($options, @l) = @_;
my $w = new Gtk::Table(0, 0, $options->{homogeneous} || 0);
map_index {
my ($i, $l) = ($_[0], $_);
map_index {
my ($j) = @_;
if ($_) {
ref $_ or $_ = new Gtk::Label($_);
$j != $#$l ?
$w->attach($_, $j, $j + 1, $i, $i + 1, 'fill', 'fill', 5, 0) :
$w->attach($_, $j, $j + 1, $i, $i + 1, 1|4, ref($_) eq 'Gtk::ScrolledWindow' ? 1|4 : 0, 0, 0);
$_->show;
}
} @$l;
} @l;
$w->set_col_spacings($options->{col_spacings} || 0);
$w->set_row_spacings($options->{row_spacings} || 0);
$w
}
sub createScrolledWindow {
my ($W, $policy) = @_;
my $w = new Gtk::ScrolledWindow(undef, undef);
$policy ||= [ 'automatic', 'automatic'];
$w->set_policy(@{$policy});
member(ref $W, qw(Gtk::CList Gtk::CTree Gtk::Text)) ?
$w->add($W) :
$w->add_with_viewport($W);
$W->can("set_focus_vadjustment") and $W->set_focus_vadjustment($w->get_vadjustment);
$W->show;
$w
}
sub create_treeitem {
my ($name) = @_;
my ($next_child, $left, $right, $up, $down);
$next_child = sub {
my ($c, $dir) = @_;
my @childs = $c->parent->children;
my $i; for ($i = 0; $i < @childs; $i++) { last if $childs[$i] == $c || $childs[$i]->subtree == $c }
$i += $dir;
0 <= $i && $i < @childs ? $childs[$i] : undef;
};