#!/usr/bin/perl -w
################################################
# fbconfig.pl
# --Configuration program fro blackbox, fluxbox, etc.
#
#TODO:
# --code add/update btns for men editor
# --save menu file
# --
# --code init file editor
# --
# --code style file editor
# --
# --code status bar
# --
# --split this file into smaller files
##################################################
use Gtk2;
#use strict;
use Gtk2::Gdk::Keysyms;
use Data::Dumper;
init Gtk2;
use constant FALSE => 0;
use constant TRUE => 1;
use constant TEST =>1;
### Global Variables ###
my $menufile="~/.fluxbox/menu";
my $initfile="~/.fluxbox/init";
my $stylesdir="~/.fluxbox/styles";
my $stylefile="";
my $context_id;
my $current_doc_isTainted = FALSE;
my $statusText="";
##################
### GUI Elements###
my $mw = new Gtk2::Window( 'toplevel' );
my $main_box = new Gtk2::VBox( 0, 0 );
my $menu_box = new Gtk2::HBox( 1, 0 );
my $menubar = new Gtk2::MenuBar();
my $toolbar_box = new Gtk2::HBox( 0, 0 );
my $toolbar = new Gtk2::Toolbar;
my $notebook_box = new Gtk2::HBox( 0, 0 );
my $notebook = new Gtk2::Notebook();
my $menuEdit_box= new Gtk2::HPaned();
my $menuTree_view = new Gtk2::ScrolledWindow( 0,0 );
my $menuTree = new Gtk2::TreeView();
my $menu_selection;
my $menuTreeModel=Gtk2::TreeStore->new(qw/ Glib::String Glib::String Glib::String /);
my $selected; #current selection
use constant NAMECOL=>0;
use constant FXNCOL=>1;
use constant CMDCOL=>2;
use constant ICNCOL=>3;
use constant NUMCOLS=>3;
my $menuEditor_view=new Gtk2::Table( 10, 3, 1 );
my $menueditor_frame=new Gtk2::Frame( "Options" );
my $initEdit_box= new Gtk2::HPaned();
my $styleEdit_box= new Gtk2::HPaned();
my $status_box = new Gtk2::HBox( 0, 0 );
my $status = new Gtk2::Statusbar();
my $filesel = new Gtk2::FileSelection( "Select File" );
######################################
### Editing Panes ###
######################################
######################################
### Menu Edit ###
#Title column
my $renderer = Gtk2::CellRendererText->new;
$renderer->set (xalign => 0.0);
my $col_offset = $menuTree->insert_column_with_attributes
(-1, "Title", $renderer,
text => NAMECOL);
my $column = $menuTree->get_column ($col_offset - 1);
$column->set_clickable (TRUE);
#Type column
$renderer = Gtk2::CellRendererText->new;
$renderer->set (xalign => 0.0);
$col_offset = $menuTree->insert_column_with_attributes
(-1, "Type", $renderer,
text => FXNCOL);
$column = $menuTree->get_column ($col_offset - 1);
$column->set_clickable (TRUE);
#Command column
$renderer = Gtk2::CellRendererText->new;
$renderer->set (xalign => 0.0);
$col_offset = $menuTree->insert_column_with_attributes
(-1, "Command", $renderer,
text => CMDCOL);
$column = $menuTree->get_column ($col_offset - 1);
$column->set_clickable (TRUE);
$menuTree->set_rules_hint (TRUE);
#$menuTree->signal_connect( "select_cursor_row", \&select_row );
$menuTree->show;
my $function_entry = new Gtk2::Entry;
my $function_sel = new Gtk2::OptionMenu;
my $title_entry = new Gtk2::Entry();
my $cmd_entry = new Gtk2::Entry();
my $browse_btn = new Gtk2::Button('Browse');
my $add_btn = new Gtk2::Button('Add');
my $update_btn = new Gtk2::Button('Update');
#build popup function menu
my @Fxn_Menu=('Submenu',
'Exec',
'Include',
'Nop',
'Style',
'StylesDir',
'StylesMenu',
'Reconfig',
'Restart',
'Workspaces');
$function_sel->set_menu(&getMenu(@Fxn_Menu));
$function_sel->signal_connect( "changed", sub {$function_entry->set_text( $Fxn_Menu[$function_sel->get_history])});
$function_sel->show;
$function_entry->show;
$add_btn->signal_connect( "clicked", sub{update_tree("add");});
$update_btn->signal_connect( "clicked", sub{update_tree("update");});
$menuEditor_view->attach( (new Gtk2::Label("Function:")), 0, 1, 1, 2, [], [], 0, 0 );
$menuEditor_view->attach( $function_entry, 1, 3, 1, 2, ['fill','expand','shrink'], [], 0, 0 );
$menuEditor_view->attach( $function_sel, 3, 4, 1, 2, ['fill','expand','shrink'], [], 0, 0 );
$menuEditor_view->attach( (new Gtk2::Label("Menu Title:")), 0, 1, 2, 3, [], [], 0, 0 );
$menuEditor_view->attach_defaults( $title_entry, 1, 4, 2, 3);
$menuEditor_view->attach( (new Gtk2::Label("Command:")), 0, 1, 3, 4, [], [], 0, 0 );
$menuEditor_view->attach( $cmd_entry, 1, 3, 3, 4, ['fill','expand','shrink'], [], 0, 0 );
$menuEditor_view->attach( $browse_btn, 3, 4, 3, 4, [], [], 0, 0 );
$menuEditor_view->attach( $add_btn, 2, 3, 5, 6, [], [], 0, 0 );
$menuEditor_view->attach( $update_btn, 3, 4, 5, 6, [], [], 0, 0 );
$menuEditor_view->show_all();
$menuTree_view->add_with_viewport($menuTree);
$menuTree_view->show_all();
$menueditor_frame->add($menuEditor_view);
$menueditor_frame->set_label_align(.5,0);
$menueditor_frame->set_shadow_type('etched_out');
$menueditor_frame->show;
$menuEdit_box->pack1( $menuTree_view, 1, 1 );
$menuEdit_box->pack2( $menueditor_frame, 1, 1 );
$menuEdit_box->show;
### Menu Edit ###
######################################
######################################
### Init Edit ###
$initEdit_box->show();
### Init Edit ###
######################################
######################################
### Style Edit ###
$styleEdit_box->show();
### Style Edit ###
######################################
######################################
### Widows ###
######################################
######################################
### Main Window ###
#set window props
$mw->set_title( "FBConfig" );
$mw->set_default_size (600, 400);
$mw->signal_connect( "destroy"=> \&exit_app );
$mw->realize();
###############
### menubar ###
my $file_mnu_root = new Gtk2::MenuItem( "File" );
my $file_mnu = new Gtk2::Menu();
my $open_item = new Gtk2::MenuItem( "Open" );
$file_mnu->append( $open_item );
$open_item->signal_connect( 'activate', sub{$filesel->show();} );
$open_item->show();
my $save_item = new Gtk2::MenuItem( "Save" );
$file_mnu->append( $save_item );
$save_item->signal_connect( 'activate', \&file_save );
$save_item->show();
my $quit_item = new Gtk2::MenuItem( "Quit" );
$file_mnu->append( $quit_item );
$quit_item->signal_connect( 'activate', \&exit_app );
$quit_item->show();
$file_mnu_root->set_submenu( $file_mnu );
$file_mnu_root->show();
my $help_mnu_root = new Gtk2::MenuItem( "Help" );
my $help_mnu = new Gtk2::Menu();
my $help_item = new Gtk2::MenuItem( "Help" );
$help_mnu->append( $help_item );
$help_item->signal_connect( 'activate', \&show_help );
$help_item->show();
my $about_item = new Gtk2::MenuItem( "About" );
$help_mnu->append( $about_item );
$about_item->signal_connect( 'activate', \&show_about );
$about_item->show();
$help_mnu_root->set_submenu( $help_mnu );
$help_mnu_root->show();
$menubar->append( $file_mnu_root );
$menubar->append( $help_mnu_root );
$menubar->show();
$menu_box->pack_start( $menubar, 1, 1, 0 );
$menu_box->show();
### menubar ###
###############
###############
### toolbar ###
$toolbar->insert_stock ('gtk-open',
"Opens File for editing.",
undef,
sub{$filesel->show();},
$mw, # user data for callback
-1); # -1 means "append"
$toolbar->insert_stock ('gtk-quit',
"Quits",
undef,
\&exit_app,
$mw, # user data for callback
-1); # -1 means "append"
$toolbar->append_space;
#$toolbar->border_width( 0 );
#$toolbar->set_space_size( 0 );
#my $open_button = $toolbar->append_item( "Open",
# "Open a file",
# "Private",
# &getImage("open") );
# $open_button->signal_connect( "clicked", sub{$filesel->show();} );
#my $close_button = $toolbar->append_item( "Close",
# "Close this app",
# "Private",
# &getImage("exit") );
# $close_button->signal_connect( "clicked", \&exit_app );
$toolbar->show();
$toolbar_box->pack_start( $toolbar, 1, 1, 0 );
$toolbar_box->show();
### toolbar ###
############
##############
### NoteBook ###
$notebook->set_tab_pos( 'top' );
$notebook->append_page($menuEdit_box, (new Gtk2::Label( "Menu" )));
$notebook->append_page($initEdit_box, (new Gtk2::Label( "Init" )));
$notebook->append_page($styleEdit_box, (new Gtk2::Label( "Style" )) );
$notebook->show();
$notebook_box->pack_start( $notebook, 1, 1, 1 );
$notebook_box->show();
### NoteBook ###
##############
##############
### Status Bar ###
my @context_id;
showStatus("Welcome to $0");
$status->show();
$status_box->pack_start( $status, 1, 1, 0 );
$status_box->show();
### Status Bar ###
##############
$main_box->pack_start($menu_box , 0, 0, 0);
$main_box->pack_start( $toolbar_box , 0, 0, 0);
$main_box->pack_start( $notebook_box , 1, 1, 0);
$main_box->pack_start( $status_box , 0, 0, 0);
$main_box->show;
$mw->add( $main_box );
### Main Window ###
######################################
######################################
### File Selection Dialog ###
# Connect the ok_button to file_ok_sel function
$filesel->ok_button->signal_connect( "clicked",
\&file_ok_sel,
$filesel );
# Connect the cancel_button to destroy the widget
$filesel->cancel_button->signal_connect( "clicked",
sub { $filesel->destroy; } );
# Set the filename,
$filesel->set_filename( $menufile );
### File Selection Dialog ###
######################################
#$mw->add( $mainlayout );
$mw->show;
Gtk2->main;
#Gtk2->main_quit;
exit 0 ;
######################################
### Global Routines ###
######################################
sub file_ok_sel
{
my ( $widget, $file_selection ) = @_;
$menufile = $file_selection->get_filename();
#print( "$menufile\n" );
&makemodel();
$file_selection->destroy;
}
#this just manipulates the status ba. Pass in the string to display as a parameter.
sub showStatus{
my ( $statusText) = @_;
if ($context_id[0]){
pop @context_id;
}
push (@context_id , $status->get_context_id( "$statusText" ) );
$status->push( $context_id[-1], $statusText );
}
#
# getImage() is used to display the toolbar images.
# The parameter is the name of the file in pixmaps/, without the .xpm extension.
#
sub getImage {
my $file = "pixmaps/".$_[0].".xpm";
if (-e $file){
my ( $icon, $mask ) = Gtk2::Gdk::Pixmap->create_from_xpm( $mw->window,
$mw->style->white,
$file );
return ( new Gtk2::Pixmap( $icon, $mask ) );
} else {
return undef;
}
}
#
# Place all closing code here.
# If a doc hasn't been saved, then ask to save it.
sub exit_app {
if ($current_doc_isTainted) {
#prompt user to save
}
#$mw->destroy;
Gtk2->main_quit;
exit 0;
}
# this function actually creates the menu tree.
sub makemodel {
my @nodes;
open (MENUFILE, $menufile) || return;
foreach $thistr (<MENUFILE>){
#chomp;
#my $thistr=$_;
if ($thistr=~m/^\s*#/){
#do nothing
} elsif ($thistr=~m/\[(\s*)begin(\s*)\]/){ #begins menu
$thistr=~m/\(.*\)/; #matches name of menu
$thistr=$&; #thistr= name of menu
$thistr=~s/\(//;$thistr=~s/\)//; #delete parens
push(@nodes, $menuTreeModel->append(undef) ); #add to tree as node
$menuTreeModel->set($nodes[-1],NAMECOL,"$thistr" ); #fill in vals in row
} elsif ($thistr=~m/\[(\s)*submenu(\s)*\]/){
$thistr=~m/\(.*\)/;
$thistr=$&;
$thistr=~s/\(//;$thistr=~s/\)//;
push(@nodes, $menuTreeModel->append( $nodes[-1] ) ) ;
$menuTreeModel->set($nodes[-1],NAMECOL,"$thistr" );
} elsif ($thistr=~m/\[(\s)*end(\s)*\]/){
pop (@nodes);
} else {
my $temp=$thistr;
$temp=~m/\[.*\]/;
my $fxn=$&;$fxn=~s/\[//;$fxn=~s/\]//;
$temp=$thistr;$temp=~m/\(.*\)/;
my $title=$&;$title=~s/\(//;$title=~s/\)//;
$temp=$thistr;$temp=~m/\{.*\}/;
my $cmd=$&;
$cmd=~s/\{//;$cmd=~s/\}//;
#showStatus( "Number of Iters in \@parentIters is $nodes[-1] \n");
if($title){
my $childIter=$menuTreeModel-> append($nodes[-1]);
$menuTreeModel-> set( $childIter, NAMECOL,"$title", FXNCOL,"$fxn",CMDCOL,"$cmd" );
}
}
}
close (MENUFILE);
$menuTree->set_model($menuTreeModel);
$menuTree->set_expander_column (NAMECOL);
$menu_selection = $menuTree->get_selection;
$menu_selection->set_mode ('browse');
$menu_selection->signal_connect (changed => \&select_row, $menuTreeModel);
#$menuTree->signal_connect (row_activated => \&row_activated, $menuTreeModel);
}
#this is just here so select_row can work. don't ask me why, but it needs to be here.
sub row_activated {
}
#
# Callback when a row is selected
#
sub select_row {
my ($selection, $model) = @_;
$selected = $selection->get_selected;
showStatus("Could not get selection.\n") if !($selected);
return unless $selected;
my $title = $model->get ($selected, NAMECOL);
my $fxn = $model->get ($selected, FXNCOL);
my $cmd = $model->get ($selected, CMDCOL);
#my $icn = $model->get ($selected, ICNCOL);
$title_entry->set_text( $title ) if $title;
$cmd_entry->set_text( $cmd ) if $cmd;$cmd_entry->set_text("") if !($cmd);
$function_entry->set_text( $fxn ) if $fxn;$function_entry->set_text("") if !($fxn);
$fxn="Submenu" if !($fxn);
$function_sel->set_history( &which_index($fxn,@Fxn_Menu) );
}
#which_index takes a string and an array and returns the index of that string in the array
# For my purposes, it is only used to change the value of the option menu for the
# menu editor when a row is selected.
sub which_index{
local ($str,@ompare)=@_;
local ($cnt,$ret)=0;
foreach $i (@ompare){
$ret=$cnt if ( lc($str) eq lc($i) );
$cnt++;
}
return $ret;
}
#getMenu() returns a menu widget based on an array. Used for the menueditor->popupmenu
sub getMenu {
my @list = @_;
my $menu = Gtk2::Menu->new;
my $menuitem;
#$menu->set_title($list[0]);
my $i;
foreach $i (@list){
$menuitem = Gtk2::MenuItem->new_with_label ($i);
$menu->append($menuitem);
$menuitem->show;
}
return $menu;
}
#updates item to menutree
#to update:
# $menuTreeModel->set_value($iter, $column,$value)
# $menuTreeModel->set($iter, COL1, $value1, COL2, $value2, ... ,-1)
#to add:
# $iter=$menu_selection->get_selection()
# $menuTreeModel->insert_after($iter)
sub update_tree {
my ($type)=@_;
local $iter;
$menu_selection = $menuTree->get_selection;
$iter = $menu_selection->get_selected;
$path=$menuTreeModel->get_path($iter)->to_string;
if ($type eq 'add'){
$iter=$menuTreeModel->insert_after('',$iter);
$path=$menuTreeModel->get_path($iter)->to_string;
showStatus("Added to $path.");
}
if ($type eq 'update'){
showStatus("Updated $path.");
}
$menuTreeModel-> set( $iter,
NAMECOL,$title_entry->get_text,
CMDCOL,$cmd_entry->get_text,
FXNCOL,lc($function_entry->get_text) );
}
#
#this function saves the file
#
sub file_save {
my $out="#this file generated by fbConfig by Skaman Sam . Copyleft 2003.\n";
my @spaceholder;
#$menuTreeModel->foreach(\&printrow,\$out);
#my $iter=$menuTreeModel->get_iter_first;
$path=new_first Gtk2::TreePath;
get_child($menuTreeModel,$path,\$out);
warn ($out);
}
sub get_child{
local ($model,$path,$out)=@_;
local $iter=$model->get_iter($path);
#warn "iter has ".$model->iter_n_children($iter)." children.\n";
for (my $cnt=0; $cnt<$model->iter_n_children($iter);$cnt++){
#local $parent=$model->get_iter($path);
#$model->iter_parent($parent);
$iter=$model->iter_nth_child($model->iter_parent($parent),$cnt);
local $name=$model->get ($iter, NAMECOL) if ($model->get ($iter, NAMECOL));
local $fxn=$model->get ($iter, FXNCOL) if ($model->get ($iter, FXNCOL));
local $cmd=$model->get ($iter, CMDCOL) if ($model->get ($iter, CMDCOL));
#$$out.=join(@spaceholder," ");
$$out.="[".$fxn."] " if $fxn;
$$out.="(".$name.") " if $name;
$$out.="{".$cmd."}" if $cmd;
$$out.="\n";
warn $$out;
#$model->iter_next($iter);
if ($model->iter_has_child($iter)){
$path->down;
get_child($model,$path,$out);
} else {
}
}
$$out.="[end]\n";
}
#
#this function is used to traverse a Gtk2::TreeModel and output all data in the tree to a variable
#printrow() takes a few variables
# $treeStore => the Gtk2::Treestore you want to read from (passed in auto. by foreach())
# $TreePath => the Gtk2::TreePath you want to read from (passed in auto. by foreach())
# $CurIter => the Gtk2::TreeModel->get_iter you want to read from (passed in auto. by foreach())
# \$in => the data you want to add to
#
sub printrow{
local ($model,$treePath,$iter,$out) = @_;
#if no iter, then return and end traversal
return TRUE if (!$iter);
#prints the path of the current iter
#$$out.=$treePath->to_string if TEST;
#adds the submenu and begin parts to the output
if($model->iter_has_child($iter)){
if ($treePath->to_string eq '0'){
$$out.="[begin] " ;
} else {
$$out.="[submenu] ";
}
push(@spaceholder," ");
}
local $name=$model->get ($iter, NAMECOL) if ($model->get ($iter, NAMECOL));
local $fxn=$model->get ($iter, FXNCOL) if ($model->get ($iter, FXNCOL));
local $cmd=$model->get ($iter, CMDCOL) if ($model->get ($iter, CMDCOL));
$$out.=join(@spaceholder," ");
$$out.="[".$fxn."] " if $fxn;
$$out.="(".$name.") " if $name;
$$out.="{".$cmd."}" if $cmd;
$$out.="\n";
#adds the '[end]' to the end of the submenu
#local $tmpPath= new Gtk2::TreePath;
$tmpIter=$model->get_iter_first;
$tmpIter=$iter;
if (! $model->iter_next($tmpIter)){
if ($treePath->to_string eq '0'){
} else {
$$out.=join(@spaceholder," ");
$$out.="[end]\n";
pop(@spaceholder);
return FALSE;
}
}
$model->iter_prev($iter);
#$in.=$out;
#warn $out;
return FALSE;
}
|