=head NAME: DESCRIPTION: 拷贝层别比对 PARAMETER: [ { name : 'units', title : 'genesis units:', type : 'ComboBox', property : { size_policy:'Expanding,Fixed', item_list:[ {name:'mm',text:'mm'}, {name:'inch',text:'inch'}, ], tool_tip:'脚本运行genesis的工作单位,如未设置,默认为inch' }, pack : {row:1,column:1}, }, { name : 'step_filter', type : 'LineEdit', title : 'step过滤:', pack : {row:0,column:1}, property:{tool_tip:'脚本参数若未设置,则手动选择'}, }, { name : 'source_step_filter', type : 'LineEdit', title : '来源step过滤:', pack : {row:0,column:1}, property:{tool_tip:'脚本参数若未设置,则手动选择'}, }, { name : 'mode', type : 'ComboBox', title : '工作模式:', property : {tool_tip:'如未设置,则默认为拷贝层', size_policy:'Expanding,Fixed', item_list:[ {name:'copy',text:'拷贝层'}, {name:'compare',text:'拷贝并比对层'}, ] }, pack : {row:1,column:1}, }, { name : 'layer_type', type : 'ComboBox', title : '工作层别:', property : { size_policy:'Expanding,Fixed', item_list:[ {name:'drill',text:'钻孔层'}, {name:'inner',text:'内层'}, {name:'outer',text:'外层'}, {name:'sm',text:'防焊层'}, {name:'silk',text:'文字层'}, {name:'board',text:'board层'}, {name:'all',text:'所有层'}, {name:'select',text:'选择层'}, ], tool_tip:'脚本层如未设置,默认为 board' }, pack : {row:1,column:1}, }, { name : 'cmp_tol', type : 'LineEdit', title : '比对公差:', property:{tool_tip:'未设定,则默认为0.001inch,具体单位参考 units'}, }, { name : 'map_layer_res', type : 'LineEdit', title : '对比层解析度', property:{tool_tip:'未设定,则默认为0.150inch,具体单位参考 units'}, }, { name : 'layer_suffix', type : 'LineEdit', title : '层后缀:', pack : {row:0,column:1}, property:{tool_tip:'脚本参数若未设置,则默认:_bk'}, }, { name : 'ignore_attr', type : 'LineEdit', title : '忽略属性', pack : {row:0,column:1}, property:{tool_tip:'脚本参数若未设置,则默认:空'}, }, { name : 'del_backup', type : 'RadioBox', title : self.ttr('删除备份层'), property : {tool_tip:'未设定,则默认no',size_policy:'Expanding,Fixed',item_list:[{name:'yes',text:'Yes'},{name:'no',text:'No'}]}, pack : {row:9,column:1}, validate: function(obj,val,title,moment){ print(title +' changed to <' + val + '> on ' + moment); } }, { name : 'save_job', title : '保存料号', type : 'RadioBox', property : { size_policy:'Expanding,Fixed', item_list:[ {name:'Yes',text:'Yes'}, {name:'No',text:'No'}, ], tool_tip:'脚本结束后自动保存料号,未设定,默认为No' }, pack : {row:1,column:1}, }, ] VERSION_HISTORY: V1.00 2019-05-26 Shyer 1.新版本 HELP: <html><body bgcolor="#DDECFE"> <font size="3" color="#003DB2"><p>功能简介</p></font> <p> 拷贝层别比对 </p> <br> <font size="3" color="#003DB2"><p>参数配置</p></font> <font color="#008000"><p> ● 无</p></font> <font size="3" color="#003DB2"><p>注意事项</p></font> <p> ● 无 </p> <br> </body></html> =cut use strict; #my ($JOB,$GEN,$GUI,$DB,$JOB_ID,$PAR,$APP,$MW); use utf8; use File::Spec; use Data::Dump 'dump'; my $Return = 'done'; my $Job = $JOB; $PAR->{mode} = 'copy' unless $PAR->{mode}; $PAR->{layer_suffix} = '_bk' unless $PAR->{layer_suffix}; $PAR->{units} = 'inch' unless $PAR->{units}; unless ($PAR->{cmp_tol}){ $PAR->{cmp_tol} = $PAR->{units} eq 'inch' ? 0.001 : 0.0254; } $PAR->{cmp_tol} *= 1000; unless ($PAR->{map_layer_res}){ $PAR->{map_layer_res} = $PAR->{units} eq 'inch' ? 0.15 : 3.81; } $PAR->{map_layer_res} *= 1000; $PAR->{step_filter} = '.*' unless $PAR->{step_filter}; $PAR->{layer_type} = 'board' unless $PAR->{layer_type}; $PAR->{del_backup} = 'no' unless $PAR->{del_backup}; $PAR->{save_job} = 'No' unless $PAR->{save_job}; use_module("PubFunction"); my $Func = PubFunction->new(); try { show_loading("判断是否选择料号..",0,position=>'n'); unless( $Job){ $GUI->msgbox(-icon=>'error',-text=>"请先选择料号后再执行脚本!"); return 'Cancel'; } ## update_loading("检查${Job}是否存在..",0,position=>'n'); unless ( $GEN->isJobExists(job=>$Job) ){ $GUI->msgbox(-icon=>'error',-text=>"料号${Job}不存在,请确认。"); return 'Cancel'; } update_loading("正在打开料号...",0,position=>'n'); $GEN->openJob(job=>$Job) unless ($GEN->isJobOpen(job=>$Job)); ## my $info = ui_confirm(); return $info if $info eq 'Cancel'; ## my $Step = $info->{step}; my $source_job = $info->{source_job}; my $source_step = $info->{source_step}; my $tol = $info->{tolerance}; my $suffix = $info->{suffix}; my @Layers = @{$info->{layers}}; $GEN->openStep(job=>$Job,name=>$Step); $GEN->clearLayers(); $GEN->affectedLayer( mode=>'all',affected=>'no' ); $GEN->units( type=>$PAR->{units} ); $GEN->zoomHome(); my @report; my (%info,%cmp); if($PAR->{mode} =~ /compare/){ $info{title} = "$Step 和$source_job 的$source_step 中层别比对结果"; $info{width} = 300; $info{columns} = [{name=>'layer',label=>'工作层'},{name=>'source_layer',label=>'比对层'},{name=>'source_step',label=>'来源step'},{name=>'result',label=>'比对结果'}]; } my (@tmp_layers,@bk); foreach my $item( @Layers ){ next unless $item->{target_layer}; update_loading("正在从$source_job 中的 $source_step step 的$item->{source_layer}层 拷贝到$item->{target_layer} ",0,position=>'n'); my $bk_layer = $item->{source_layer}.$suffix; push @bk,$bk_layer; $GEN->copyLayer(source_job=>$source_job,source_step=>$source_step,source_layer=>$item->{source_layer},dest_layer=>$bk_layer,mode=>'replace',invert=>'no') ; #if($PAR->{mode} =~ /compare/){ # my $map_layer = 'cmp_'.$item->{target_layer}; # push @tmp_layers,($map_layer,$bk_layer); # update_loading("$item->{target_layer} 层正在和$source_job 中的 $source_step step 的$item->{source_layer}层 ",0,position=>'n'); # my $diff = $GEN->compareLayers( # layer1 => $item->{target_layer},job2 => $Job,step2 => $Step,layer2 => $bk_layer,layer2_ext => '', # tol => $tol, area => 'global',ignore_attr => $PAR->{ignore_attr},map_layer => $map_layer,map_layer_res=>$PAR->{map_layer_res}); # if( $diff ){ # push @{$info{data}},{layer=>$item->{target_layer},source_layer=>$bk_layer,source_step=>$source_step,result=>'NG',result_bg=>'red'}; # $cmp{$item->{target_layer}}{source} = $item->{source_layer}; # $cmp{$item->{target_layer}}{ref} = $bk_layer; # $cmp{$item->{target_layer}}{map} = $map_layer; # $cmp{$item->{target_layer}}{diff} = 1; # # } # else{ # push @{$info{data}},{layer=>$item->{target_layer},source_layer=>$bk_layer,source_step=>$source_step,result=>'OK',result_bg=>'green'}; # } #} } if ($info->{del_nfp} eq 'yes') { $GEN->affectedLayer(affected=>'yes',layer=>[@bk],clear_before=>'yes'); my $check_list = 'nfp'; unless ( $GEN->isChklistExists(job=>$Job,step=>$Step,chklist=>$check_list) ){ $GEN->COM('chklist_from_lib',chklist=>$check_list); } $GEN->COM('chklist_open',chklist=>$check_list); $GEN->COM('chklist_show',chklist=>$check_list); $GEN->chklistCupd(chklist=>$check_list,nact=>1,params=>{pp_layer=>'.affected',pp_drill=>'Via'}) ; $GEN->COM('chklist_run',chklist=>$check_list,nact=>1,area=>'global'); #$GEN->COM('chklist_res_show',chklist=>$check_list,nact=>$act_num,x=>0,y=>0,w=>0,h=>0); $GEN->COM("chklist_res_sel_category,layers_mode=replace,keep_work_lyr=no,display_mode=auto_zoom,chklist=$check_list,nact=1,category=modify_text"); } foreach my $item( @Layers ){ next unless $item->{target_layer}; my $bk_layer = $item->{source_layer}.$suffix; if($PAR->{mode} =~ /compare/){ my $map_layer = 'cmp_'.$item->{target_layer}; push @tmp_layers,($map_layer,$bk_layer); update_loading("$item->{target_layer} 层正在和$source_job 中的 $source_step step 的$item->{source_layer}层 ",0,position=>'n'); my $diff = $GEN->compareLayers( layer1 => $item->{target_layer},job2 => $Job,step2 => $Step,layer2 => $bk_layer,layer2_ext => '', tol => $tol, area => 'global',ignore_attr => $PAR->{ignore_attr},map_layer => $map_layer,map_layer_res=>$PAR->{map_layer_res}); if( $diff ){ push @{$info{data}},{layer=>$item->{target_layer},source_layer=>$bk_layer,source_step=>$source_step,result=>'NG',result_bg=>'red'}; $cmp{$item->{target_layer}}{source} = $item->{source_layer}; $cmp{$item->{target_layer}}{ref} = $bk_layer; $cmp{$item->{target_layer}}{map} = $map_layer; $cmp{$item->{target_layer}}{diff} = 1; } else{ push @{$info{data}},{layer=>$item->{target_layer},source_layer=>$bk_layer,source_step=>$source_step,result=>'OK',result_bg=>'green'}; } } } # ##确认比对结果 if($PAR->{mode} =~ /compare/i ){ foreach my $item( @Layers ){ next unless $cmp{$item->{target_layer}}{diff}; $Return = 'warning'; $GEN->workLayer(name=>$item->{target_layer},display_number=>1,clear_before=>'yes'); $GEN->displayLayer(name=>$cmp{$item->{target_layer}}{ref},number=>2); $GEN->displayLayer(name=>$cmp{$item->{target_layer}}{map},number=>3); update_loading("$item->{target_layer} 和$source_job 中的 $source_step step 的$cmp{$item->{target_layer}}{source}层比对结果不一致,请确认",0,position=>'n'); my $ans = $GEN->PAUSE('Please Check'); return 'Cancel' unless $ans eq 'OK'; } $GEN->deleteLayer(job=>$Job,layer=>[@tmp_layers]) if $PAR->{del_backup} =~ /yes/i; } ##解析报告格式 if( keys %info ){ push @report,$Func->format_report_data(-rows=>\%info); ##储存比对报告 if( @report ){ my $Report = join('.',@report); $GUI->msgbox(-text=>'info',-text=>'请在制作结果中查看比对结果'); $IKM->update_flow_report(-report=>$Report,-job_id=>$ARGS{job_id},-process_id=>$ARGS{process_id}); } else{ $IKM->update_flow_report(-report=>'',-job_id=>$ARGS{job_id},-process_id=>$ARGS{process_id}); } } else{ $IKM->update_flow_report(-report=>'',-job_id=>$ARGS{job_id},-process_id=>$ARGS{process_id}); } hide_loading(); ##保存料号 if( $PAR->{save_job} =~ /yes/i ){ show_loading("$Job 正在保存料号,请稍候...",0,position=>'n'); $GEN->checkInout(job=>$Job,mode=>'out'); $GEN->saveJob(job=>$Job); hide_loading(); } unless ($GEN->{STATUS}){ return $Return; } else{ $GUI->msgbox(-icon=>'error',-text=>join("\n",@{$GEN->{STATUS}})); addFlowNotes(-notes=>" Genesis Error:\n ".join("\n ",@{$GEN->{STATUS}})); return 'Error'; } } catch Error::Simple with { my $error = encode("utf8",shift); $GUI->msgbox(-icon=>'error',-text=>$error); return 'Error'; } finally{ #$GEN->deleteLayer(layer=>$tmp_layer) if ($GEN->isLayerExists(job=>$Job,layer=>$tmp_layer)); }; sub _layer_bg_color{ my $it = shift; if ($it->{context} eq 'board'){ if ($it->{layer_type} eq 'signal'){ return '#FDC74D'; } elsif ($it->{layer_type} eq 'power_ground'){ return '#DBAD00'; } elsif ($it->{layer_type} eq 'mixed'){ return '#F3E086'; } elsif ($it->{layer_type} eq 'solder_mask'){ return '#00A57C'; } elsif ($it->{layer_type} eq 'silk_screen'){ return '#FFFFFF'; } elsif ($it->{layer_type} eq 'solder_paste'){ return '#FFFFCE'; } elsif ($it->{layer_type} eq 'drill'){ return '#9BB5BF'; } elsif ($it->{layer_type} eq 'rout'){ return '#D9D9D9'; } elsif ($it->{layer_type} eq 'document'){ return '#9BDBDB'; } } else{ return '#9BDBDB'; } } sub ui_confirm{ my %par = @_; update_loading("确认层别的拷贝和比对信息...",0,position=>'n'); my $JobList; my @items; push @items,( { name => 'job', label => '当前料号', type => 'job', property => { tl_joblist => sub{$JobList = $GEN->getJobList() unless $JobList;return $JobList}, }, value=>$Job, sensitive =>0, validate_func => sub{ my %par = @_; if ($par{mode} ne 'save'){ if ($par{value} ne ''){ ## my @all_steps = $GEN->getStepList(job=>$par{value}); my @tl_data_target; foreach my $step( @all_steps){ push @tl_data_target,{step=>$step}; } $par{formpanel}->get_widget('step')->set_property(tl_data=>[@tl_data_target]); ## my @step_filter = grep(/$PAR->{step_filter}/,@all_steps); if(@step_filter){ if(scalar(@step_filter) == 1){ $par{formpanel}->set_value('step',$step_filter[0]); } } ## my $source_job = $par{formpanel}->get_value('source_job'); my $source_matrix = $GEN->getMatrix(job=>$source_job); ## $par{formpanel}->{TARGET_LAYER_MATRIX} = $GEN->getMatrix(job=>$par{value}); my $matrix = $par{formpanel}->{TARGET_LAYER_MATRIX}; my @layer_default; foreach my $layer(sort {$matrix->{$a}{row} <=> $matrix->{$b}{row}} keys %{$matrix} ) { if( $PAR->{layer_type} =~ /board/ ){ if( defined $matrix->{$layer}{context} and $matrix->{$layer}{context} eq 'board' ){ if( $source_matrix->{$layer} ){ push @layer_default,{target_layer=>$layer,source_layer=>$layer}; } else{ push @layer_default,{target_layer=>$layer}; } } } elsif( $PAR->{layer_type} =~ /all/ ){ if( $source_matrix->{$layer} ){ push @layer_default,{target_layer=>$layer,source_layer=>$layer}; } else{ push @layer_default,{target_layer=>$layer}; } } elsif( $PAR->{layer_type} =~ /drill/ ){ if( $matrix->{$layer}{context} eq 'board' and $matrix->{$layer}{layer_type} eq 'drill' ){ if( $source_matrix->{$layer} ){ push @layer_default,{target_layer=>$layer,source_layer=>$layer}; } else{ push @layer_default,{target_layer=>$layer}; } } } elsif( $PAR->{layer_type} =~ /inner/ ){ if( $matrix->{$layer}{context} eq 'board' and $matrix->{$layer}{tl_type} eq 'inner' ){ if( $source_matrix->{$layer} ){ push @layer_default,{target_layer=>$layer,source_layer=>$layer}; } else{ push @layer_default,{target_layer=>$layer}; } } } elsif( $PAR->{layer_type} =~ /outer/ ){ if( $matrix->{$layer}{context} eq 'board' and $matrix->{$layer}{tl_type} eq 'outer' ){ if( $source_matrix->{$layer} ){ push @layer_default,{target_layer=>$layer,source_layer=>$layer}; } else{ push @layer_default,{target_layer=>$layer}; } } } elsif( $PAR->{layer_type} =~ /sm/ ){ if( $matrix->{$layer}{context} eq 'board' and $matrix->{$layer}{tl_type} eq 'solder_mask' ){ if( $source_matrix->{$layer} ){ push @layer_default,{target_layer=>$layer,source_layer=>$layer}; } else{ push @layer_default,{target_layer=>$layer}; } } } elsif( $PAR->{layer_type} =~ /silk/ ){ if( $matrix->{$layer}{context} eq 'board' and $matrix->{$layer}{tl_type} eq 'silk_screen' ){ if( $source_matrix->{$layer} ){ push @layer_default,{target_layer=>$layer,source_layer=>$layer}; } else{ push @layer_default,{target_layer=>$layer}; } } } } if( @layer_default ){ $par{formpanel}->set_value('layers',\@layer_default); } else{ $par{formpanel}->set_value('layers',[{target_layer=>''}]); } $par{formpanel}->{TARGET_LAYER_MATRIX} = $GEN->getMatrix(job=>$par{value}); } else{ $par{formpanel}->{TARGET_LAYER_MATRIX} = undef; } } if ($par{value} eq ''){ return {error_msg=>'当前料号不能为空!'} } return {}; }, pre_func => sub{ my %par = @_; $par{formpanel}->{TARGET_LAYER_MATRIX} = $GEN->getMatrix(job=>$Job); } }, { name => 'source_job', label => '来源料号', type => 'job', property => { tl_joblist => sub{$JobList = $GEN->getJobList() unless $JobList;return $JobList}, }, value=>$Job, validate_func => sub{ my %par = @_; my $work_job = $par{formpanel}->get_value('source_job'); if ($par{mode} ne 'save'){ if ($par{value} ne ''){ my @all_steps = $GEN->getStepList(job=>$par{value}); my @tl_data_source; foreach my $step( @all_steps){ push @tl_data_source,{step=>$step}; } $par{formpanel}->get_widget('source_step')->set_property(tl_data=>[@tl_data_source]); ## my @step_filter = grep(/$PAR->{source_step_filter}/,@all_steps); if(@step_filter){ if(scalar(@step_filter) == 1){ $par{formpanel}->set_value('source_step',$step_filter[0]); } } ## my $layers = $par{formpanel}->get_value('layers'); my $source_matrix = $GEN->getMatrix(job=>$work_job); my @layer_default; foreach my $item(@$layers){ if( $item->{target_layer} and $item->{source_layer} and $item->{target_layer} ne $item->{source_layer} ){ push @layer_default,{target_layer=>$item->{target_layer},source_layer=>$item->{source_layer}}; } elsif( $source_matrix->{$item->{target_layer}} ){ push @layer_default,{target_layer=>$item->{target_layer},source_layer=>$item->{target_layer}}; } else{ push @layer_default,{target_layer=>$item->{target_layer}}; } } if( @layer_default ){ $par{formpanel}->set_value('layers',\@layer_default); } ## $par{formpanel}->{SOURCE_LAYER_MATRIX} = $GEN->getMatrix(job=>$par{value}); } else{ $par{formpanel}->{SOURCE_LAYER_MATRIX} = undef; } } if ($par{value} eq ''){ return {error_msg=>'目标料号不能为空!'} } return {}; }, pre_func => sub{ my %par = @_; $par{formpanel}->{SOURCE_LAYER_MATRIX} = $GEN->getMatrix(job=>$Job); } }, ); push @items,( { name => "step", label => '工作Step', type => 'enum', property => { tl_field => ['step'=>'text'], tl_value_field => 'step', #tl_data=>\@tl_data_source, }, validate_func => sub{ my %par = @_; if ($par{value} eq ''){ return {error_msg=>'工作Step不能为空!'} } return {}; } }, { name => "source_step", label => '来源Step', type => 'enum', value=>'', property => { tl_field => ['step'=>'text'], tl_value_field => 'step', #tl_data=>\@tl_data_dest, }, validate_func => sub{ my %par = @_; if ($par{value} eq ''){ return {error_msg=>'来源Step不能为空!'} } return {}; } }, ); push @items,( { name=>'tolerance', label=>'比对精度', type=>'number', value=>$PAR->{cmp_tol}, units=>$PAR->{units} eq 'inch' ? 'mil' : 'um', must_field=>1, }, { name=>'suffix', label=>'后缀名', value=>$PAR->{layer_suffix}, must_field=>1, }, { name => 'layers', label_position => 'top', button_position => 'top', type => 'treeview', property => { tl_mapping =>['source_layer'=>'Glib::String','source_bg_color' => 'Glib::String','target_layer'=>'Glib::String','target_bg_color'=>'Glib::String'], tl_columns =>[{title => '当前层', visible => 1, resizable => 1,reorderable=>1,min_width=>50,expand=>1, renders => [{class=>'Text',text=>'target_layer','cell-background'=>'target_bg_color'}]}, {title => '来源层', visible => 1, resizable => 1,reorderable=>1,min_width=>50,expand=>1, renders => [{class=>'Text',text=>'source_layer','cell-background'=>'source_bg_color'}]}, ], tl_model_type=>'list', can_focus=>1, enable_grid_lines=>'both', tl_selection_mode=>'multiple', }, expand => 1, col_span => 2, scrolledwindow=>{}, get_value_func=>sub{my %par = @_; return $par{widget}->tl_get_model_data();}, set_value_func=>sub{ my %par = @_; my $source_matrix = $par{formpanel}->{SOURCE_LAYER_MATRIX}; my $target_matrix = $par{formpanel}->{TARGET_LAYER_MATRIX}; foreach my $item (@{$par{value}}){ my $source_layer = $source_matrix->{$item->{source_layer}}; my $target_layer = $target_matrix->{$item->{target_layer}}; $item->{source_bg_color} = _layer_bg_color($source_layer); if ($target_layer){ $item->{target_bg_color} = _layer_bg_color($target_layer); } } #print dump(\$par{value})," ===\n"; $par{widget}->tl_set_data($par{value}); }, #value=>[{source_layer=>'lyr1',target_layer=>'lyr1'},], buttons => [ { name => 'add_layer', stock=>'gtk-add',label=>'添加层别',relief=>'none',command=>sub{ my %par = @_; my $source_job = $par{formpanel}->get_value('source_job'); my $target_job = $par{formpanel}->get_value('job'); if ($source_job eq ''){ $GUI->msgbox(-icon=>'error',-text=>'请设定来源料号'); return; } if ($target_job eq ''){ $GUI->msgbox(-icon=>'error',-text=>'请设定工作料号'); return; } my $target_matrix = $par{formpanel}->{TARGET_LAYER_MATRIX}; my @layers = $GUI->select_layer(-title=>'选择层别',-layermatrix=>$target_matrix); return unless @layers; my $source_matrix = $par{formpanel}->{SOURCE_LAYER_MATRIX}; my @trv_layers; my $layres = $par{formpanel}->get_value('layers'); foreach my $layer (@layers){ my $layer_exist; foreach my $item(@$layres){ $layer_exist = 1 if $item->{target_layer} eq $layer; last if $layer_exist; } next if $layer_exist; my $source_layer = $source_matrix->{$layer}; my $target_layer = $target_matrix->{$layer}; my $tmp = {source_layer => $layer}; $tmp->{source_bg_color} = _layer_bg_color($source_layer); if ($target_layer){ $tmp->{target_layer} = $layer; $tmp->{target_bg_color} = _layer_bg_color($target_layer); } push @trv_layers,$tmp; } ## $par{formpanel}->get_widget('layers')->tl_append_data(\@trv_layers); return 0; } }, { name => 'remove_layer', stock=>'gtk-remove',label=>'移除层别',relief=>'none',command=>sub{ my %par = @_; $par{formpanel}->get_widget('layers')->tl_sel_remove(); }}, ], pre_func => sub{ my %par = @_; $par{widget}->signal_connect('row_activated' => sub{ my ($lyr) = $par{widget}->tl_get_selection(); return unless $lyr->{target_layer}; my $layer = $GUI->select_layer( -title => '设定'.$lyr->{target_layer}.'的来源层', -layermatrix => $par{formpanel}->{SOURCE_LAYER_MATRIX}, -selectmode => 'single', ); return unless defined $layer; my $target_bg_color = _layer_bg_color($par{formpanel}->{SOURCE_LAYER_MATRIX}{$layer}); $par{widget}->tl_change_sel_data([{source_layer=>$layer,source_bg_color=>$target_bg_color}],0); }); }, validate_func => sub{ my %par = @_; my @err; return {error_msg=>'请选择比对层别'} unless (@{$par{value}}); my $ok; foreach my $item (@{$par{value}}){ next unless $item->{target_layer}; if (!defined $item->{source_layer} or $item->{source_layer} eq ''){ push @err, $item->{target_layer}.'层对应的来源层不能为空!'; } else{ $ok = 1; } } unless($ok){ push @err, '必须添加拷贝层别!'; } if (@err){ return {error_msg=>join("\n",@err)}; } else{ return {}; } } }, { name => 'del_nfp', label=> '删除无功能pad', type=>'radio', value => 'no', property=>{tl_columns => 2, tl_list=>['yes' => '是', 'no' => '否'] }, }, ); my %vform = $GUI->show_form( -title => '信息确认', -defaultsize => [600,500], -columns => 2, -items =>\@items, ); return 'Cancel' unless %vform; return \%vform; } __END__