1#!/usr/bin/env perl 2# -*- perl -*- 3 4# 5# Author: Slaven Rezic 6# 7# Copyright (c) 1995-2012 Slaven Rezic. All rights reserved. 8# This is free software; you can redistribute it and/or modify it under the 9# terms of the GNU General Public License, see the file COPYING. 10# 11# Mail: slaven@rezic.de 12# WWW: http://bbbike.sourceforge.net 13# 14 15package main; 16 17## Additional files for perl2exe. 18## NOTE: This list is not maintained anymore. 19#perl2exe_include Tk/Checkbutton.pm 20 21## This works theoretically with 5.8.x, but there's a possible 22## endless loop which is solved in 5.10.0, see rt perl #41442 23## XXX Nope: still an endless loop with debian's perl 5.10.0 24## To reproduce: start bbbike, and add landstra�en layer 25#if ($] >= 5.010 || $] >= 5.008009) { 26# eval q{ use open ':locale' }; if ($] >= 5.008 && $@) { warn $@ } 27#} 28 29BEGIN { 30 if ($Devel::Trace::TRACE) { 31 $Devel::Trace::TRACE = 0; 32 warn <<EOF; 33********************************************************************** 34* NOTE: Turning -d:Trace off 35* You can turn it again on in the ptksh using 36* 37* \$Devel::Trace::TRACE = 1; 38* 39********************************************************************** 40EOF 41 } 42} 43 44use FindBin; 45use lib ("$FindBin::RealBin", 46 "$FindBin::RealBin/images", 47 "$FindBin::RealBin/lib", 48 ); 49# To create the Devel::Size output, start bbbike with: 50# env BBBIKE_DEBUG=Devel::Size ./bbbike | & grep size 51BEGIN { 52 if ($ENV{BBBIKE_DEBUG}) { 53 eval 'use BBBikeDebug'; 54 die $@ if $@; 55 } 56} 57 58BEGIN { 59 my $nosplash = grep { $_ eq '-nosplash' } @ARGV; 60 # save cmdline arguments; Tk::ProgressSplash would eat 61 # X11-specific options (maybe a bug there?) 62 my @save_ARGV = @ARGV; @ARGV = (); 63 if ($] >= 5.005 && !$^C && !$^P && !$nosplash) { 64 # XXX don't know whether this is a Tk400 or an old perl problem 65 eval { 66 require Tk::ProgressSplash; 67 my $splashtype = 'normal'; 68 # $splashtype = 'fast'; not used anymore: too unstable, 69 # fails with MSWin32, failures also seen on Linux x86_64 70 # systems. 71 $splash_screen = Tk::ProgressSplash->Show 72 (-splashtype => $splashtype, 73 "$FindBin::RealBin/images/bbbike_splash.xpm", 74 240, 90, "BBBike", 1); 75 }; warn $@ if $@; 76 } 77 @ARGV = @save_ARGV; 78 if ($nosplash) { $use_logo = 0 } 79 80 local $^W; 81 $^W = 0 if $^O eq 'MSWin32'; # to avoid "no such signal" warnings 82 83 { 84 use vars qw(@SIGTRAP_SIGNALS); 85 @SIGTRAP_SIGNALS = qw(USR1 INFO); 86 # Activate with CTRL-T on BSD systems. Possibly dangerous if forked 87 # processes are active, but works fine with -server option. 88 my $siginfo_handler = sub { 89 # Cannot use warn or STDERR because of Tk::Stderr interference 90 require Carp; 91 local $| = 1; 92 print Carp::longmess("Pid $$ currently"), "\n"; 93 }; 94 $SIG{$_} = $siginfo_handler for @SIGTRAP_SIGNALS; 95 } 96 ## Does not play well with Tk::Stderr, so do not use it anymore 97 #eval 'use sigtrap ("stack-trace", @SIGTRAP_SIGNALS)'; warn $@ if $@; 98 99 ## Not a good idea: setting this means that $? is always -1 100 #$SIG{CHLD} = 'IGNORE'; 101 102 $booting = 1; 103} 104 105use Config; 106 107## DEBUG_BEGIN 108#BEGIN{mymstat("before autouse BBBikeMail, Text::Wrap, File::Copy");} 109## DEBUG_END 110 111use BBBikeGlobalVars 1.012; 112 113# Call "autouse" as early as possible. Otherwise there will be errors, 114# if any other module requires theses modules. 115# "autouse" cannot be used on modules with non-standard import functions 116BEGIN { 117 %autouse_func = 118 ('BBBikeMail' => [qw(enter_send_mail)], 119 'Text::Wrap' => [qw(wrap)], 120 'File::Copy' => [qw(copy mv)], 121 'BBBikeGPS' 122 => [qw(gps_interface draw_gpsman_data do_draw_gpsman_data)], 123 'BBBikeWeather' 124 => [qw(wetter_dir_exists ignore_weather reset_wind update_weather 125 show_weather_db parse_wetterline analyze_wind)], 126 'BBBikeHeavy' 127 => [qw(start_followmouse stop_followmouse 128 string_eval_die load_plugins load_plugin layer_editor 129 getmap get_file_or_url get_user_agent get_uncached_user_agent delete_map 130 pdf_export svg_export perlmod_install_advice 131 show_register save_register_routes load_register_routes 132 show_calories check_available_memory 133 reload_all make_temp make_unique_temp 134 save_route_as_gpx save_route_as_kml 135 restart_bbbike_hint 136 )], 137 #XXX problems with autouse! -> what problems? 138 'BBBikeEdit' 139 => [qw(insert_point_from_canvas create_relation_from_canvas 140 ampeln_on_route radweg_open radweg_draw_canvas 141 )], 142 'BBBikeLazy' 143 => [qw(bbbikelazy_setup bbbikelazy_init bbbikelazy_clear 144 bbbikelazy_reload bbbikelazy_reload_all 145 bbbikelazy_redraw_current_view 146 bbbikelazy_add_data bbbikelazy_remove_data plotstr_on_demand)], 147 'BBBikePrint' 148 => [qw(create_postscript print_postscript toggle_legend 149 print_text_postscript print_text_pdflatex print_route_pdf 150 view_pdf print_text_windows)], 151 ); 152 while(my($k,$v) = each %autouse_func) { 153 eval "use autouse $k => qw(" . join(" ", @$v) . ");"; 154 die "Can't autouse $k: $@" if $@; 155 } 156} 157 158## This is only for the Autoloader-Hack (see "make autoload") 159#use AutoLoader 'AUTOLOAD'; 160 161## DEBUG_BEGIN 162#BEGIN{mymstat("before Tk");} 163## DEBUG_END 164 165BEGIN { 166 eval q{ use Tk; }; 167 if ($@) { 168 if ($^C) { 169 die $@; 170 } else { 171 warn $@; 172 if ($^O eq 'MSWin32' || -t STDIN) { 173 warn "Please enter RETURN to exit.\n"; 174 <STDIN>; 175 } 176 CORE::exit(1); 177 } 178 } 179} 180 181# Add ...\c\bin directory for Strawberry Perl on Windows. 182# This directory contains shared libraries e.g. libxml2. 183# Also the ...\perl\bin may be missing. 184if ($^O eq 'MSWin32' && $^X =~ m{(.*)(\\perl\\bin)\\}) { 185 my $c_bin_dir = "$1\\c\\bin"; 186 my $perl_bin_dir = "$1$2"; 187 if (-d $c_bin_dir) { 188 $ENV{PATH} .= ";$c_bin_dir"; 189 } 190 if (-d $perl_bin_dir) { 191 $ENV{PATH} .= ";$perl_bin_dir"; 192 } 193} 194 195#XXX for now disabled ... still too many bugs floating around -> what bugs? 196#use Tk::ErrorDialog; # XXX is this OK? 197use Tk::Canvas; 198use Tk::CanvasUtil; 199use File::Basename; 200## DEBUG_BEGIN 201#BEGIN{mymstat("before BBBikeUtil");} 202## DEBUG_END 203use BBBikeUtil; 204use BBBikeUtil qw(min max first clone s2hm_or_s); 205use BBBikeTkUtil qw(pack_buttonframe); 206use BBBikeVar; 207use BBBikeCalc; 208use BBBikeTrans; 209## DEBUG_BEGIN 210#BEGIN{mymstat("before Strassen");} 211## DEBUG_END 212use Strassen; 213use Strassen::Dataset; 214## DEBUG_BEGIN 215#BEGIN{mymstat("before Route");} 216## DEBUG_END 217use Route; 218## DEBUG_BEGIN 219#BEGIN{mymstat("before Karte");} 220## DEBUG_END 221use Karte; 222use Hooks; 223use VectorUtil qw(get_polygon_center point_in_polygon point_in_grid offset_line); 224## DEBUG_BEGIN 225#BEGIN{mymstat("before locale");} 226## DEBUG_END 227 228use strict; 229## DEBUG_BEGIN 230#BEGIN{mymstat("before use vars");} 231## DEBUG_END 232 233# i18n functions M and Mfmt 234BEGIN { 235 if (!eval ' 236use Msg; # This call has to be in bbbike! 2371; 238') { 239 warn $@ if $@; 240 eval 'sub M ($) { $_[0] }'; 241 eval 'sub Mfmt { sprintf(shift, @_) }'; 242 } 243} 244 245# XXX This is a hack until I decide how to do custom create_page best. 246{ 247 package My::Tk::Getopt; 248 use vars qw(@ISA); 249 @ISA = ('Tk::Getopt'); 250 251 BEGIN { *M = \&main::M } 252 253 sub _create_page { 254 my $self = shift; 255 my $current_top = $_[2]; 256 if ($current_top eq lc(M("Strecken/Punkte"))) { 257 my $current_page = $_[0]; 258 my $optnote = $_[1]; 259 $current_page = $optnote->{$current_top} if !defined $current_page; 260 my $optlist = $_[3]; 261 262 my %opt2opt; 263 for my $optdef (@{$optlist->{$current_top}}) { 264 $opt2opt{$optdef->[0]} = $optdef; 265 } 266 #use Hash::Util qw(lock_keys); lock_keys %opt2opt; 267 268 $current_page->Label( 269 -text => M"Strecken und Punkte, die beim Start von BBBike\ngezeichnet werden sollen.", 270 -justify => 'left', 271 )->pack(-anchor => 'w'); 272 my $f = $current_page->Frame->pack(-anchor => 'w'); 273 Tk::grid('x', 274 $f->Label(-text => "Berlin"), # XXX not for osm-data, there should be only one column here! 275 $f->Label(-text => M"Umland"), 276 $f->Label(-text => M"jwd"), 277 ); 278 Tk::grid($f->Label(-text => M"Stra�en"), 279 $f->Checkbutton(-variable => $self->varref($opt2opt{'str'})), 280 $f->Checkbutton(-variable => $self->varref($opt2opt{'landstr'})), 281 $f->Checkbutton(-variable => $self->varref($opt2opt{'landstrjwd'})), 282 ); 283 Tk::grid($f->Label(-text => M("Orte")."/".M("Ortsteile")), 284 $f->Checkbutton(-variable => $self->varref($opt2opt{'ortsteil'})), 285 $f->Checkbutton(-variable => $self->varref($opt2opt{'ort'})), 286 $f->Checkbutton(-variable => $self->varref($opt2opt{'ortjwd'})), 287 ); 288 Tk::grid($f->Label(-text => M"Gew�sser"), 289 $f->Checkbutton(-variable => $self->varref($opt2opt{'wasserstadt'})), 290 $f->Checkbutton(-variable => $self->varref($opt2opt{'wasserumland'})), 291 $f->Checkbutton(-variable => $self->varref($opt2opt{'wasserjwd'})), 292 ); 293 294 require Tk::Ruler; 295 $f->Ruler(-padx => 2)->rulerGrid(-columnspan => 4); 296 297 Tk::grid($f->Label(-text => M"Radwege"), 298 $f->Checkbutton(-variable => $self->varref($opt2opt{'cyclepath'})), '-', '-'); 299 Tk::grid($f->Label(-text => M"Radrouten"), 300 $f->Checkbutton(-variable => $self->varref($opt2opt{'cycleroute'})), '-', '-'); 301 Tk::grid($f->Label(-text => M"Gr�ne Wege"), 302 $f->Checkbutton(-variable => $self->varref($opt2opt{'greenway'})), '-', '-'); 303 Tk::grid($f->Label(-text => M("Ampeln")."/".M("Bahn�berg�nge")), 304 $f->Checkbutton(-variable => $self->varref($opt2opt{'ampel'})), '-', '-'); 305 Tk::grid($f->Label(-text => M"F�hren"), 306 $f->Checkbutton(-variable => $self->varref($opt2opt{'faehre'})), '-', '-'); 307 Tk::grid($f->Label(-text => M"Fl�chen"), 308 $f->Checkbutton(-variable => $self->varref($opt2opt{'flaeche'})), '-', '-'); 309 Tk::grid($f->Label(-text => M"Sehensw�rdigkeiten"), 310 $f->Checkbutton(-variable => $self->varref($opt2opt{'sehenswuerdigkeiten'})), '-', '-'); 311 Tk::grid($f->Label(-text => M"Fragezeichen"), 312 $f->Checkbutton(-variable => $self->varref($opt2opt{'fragezeichen'})), '-', '-'); 313 314 $f->Ruler(-padx => 2)->rulerGrid(-columnspan => 4); 315 316 Tk::grid('x', 317 $f->Label(-text => M"Linien"), 318 $f->Label(-text => M"Bahnh�fe"), 319 ); 320 Tk::grid($f->Label(-text => M"U-Bahn"), 321 $f->Checkbutton(-variable => $self->varref($opt2opt{'ubahn'})), 322 $f->Checkbutton(-variable => $self->varref($opt2opt{'ubahnhof'})), 323 ); 324 Tk::grid($f->Label(-text => M"S-Bahn"), 325 $f->Checkbutton(-variable => $self->varref($opt2opt{'sbahn'})), 326 $f->Checkbutton(-variable => $self->varref($opt2opt{'sbahnhof'})), 327 ); 328 Tk::grid($f->Label(-text => M"Regionalbahn"), #XXX translation is missing 329 $f->Checkbutton(-variable => $self->varref($opt2opt{'rbahn'})), 330 $f->Checkbutton(-variable => $self->varref($opt2opt{'rbahnhof'})), 331 ); 332 } else { 333 $self->SUPER::_create_page(@_); 334 } 335 } 336} 337 338## DEBUG_BEGIN 339#BEGIN{mymstat("before use your");} 340## DEBUG_END 341 342use your qw($Karte::Standard::obj $Karte::Standard::init_scrollregion 343 $Karte::GISmap::obj $Karte::Polar::obj 344 $Tk::Getopt::x11_pass_through 345 $wettermeldung2::proxy $wettermeldung2::module 346 %wettermeldung2::loc %wettermeldung2::www_site 347 $wettermeldung2::FIELD_TEMP $wettermeldung2::tk_widget 348 $Http::tk_widget 349 %GfxConvert::tmpfiles 350 $BikePower::has_xs 351 $Radwege::bez @Radwege::bbbike_category_order 352 %Radwege::category_plural 353 $FURadar::use_map $FURadar::progress 354 $PLZ::VERBOSE $Devel::Trace::TRACE 355 $Tk::Config::xlib 356 ); 357 358*transpose_ls = \&transpose_ls_slow; 359# If you don't have a FPU, maybe \&old_create_transpose_subs should be 360# used instead. 361*create_transpose_subs = \&old_create_transpose_subs_no_int; 362 363## DEBUG_BEGIN 364#BEGIN{mymstat("before use BBBikeXS");} 365## DEBUG_END 366 367# BBBikeXS functions are optional, as there are pure-perl replacements 368eval 'use BBBikeXS 0.09'; 369 370## DEBUG_BEGIN 371#BEGIN{mymstat("after use BBBikeXS");} 372## DEBUG_END 373 374# $VERSION is the version of the BBBike distribution 375$VERSION = $BBBike::VERSION; 376# Since the migration to git $PROG_REVISION is meaningless. Previously 377# it was constructed from the RCS version of this file. 378$PROG_REVISION = '3.500'; 379 380# OS related 381$progname = basename($0); 382# Note that $ENV{HOST} is not generally available (or sometimes only 383# as a shell variable with the same name), especially in my non-tcsh 384# configurations. 385$devel_host = ($ENV{HOST} && $ENV{HOST} =~ /^(biokovo|biokovo-amd64|mosor|vran|cabulja|cvrsnica|spiff|mom|devpc01|devpc01-debian)(\.|$)/i); 386$os = $^O eq 'MSWin32' || $^O eq 'os2' || $^O eq 'dos' ? 'win' 387 : $^O eq 'MacOS' ? 'mac' 388 : 'unix'; 389$os_bsd = $^O =~ /bsd/i; 390 391$^W = $devel_host; # $advanced also sets $^W, see below 392 393if (!defined $is_handheld) { 394 $is_handheld = $Config{"archname"} =~ /^arm-linux$/i; 395} 396$use_clipboard = 1 if $os eq 'win'; 397 398# include after setting $os! 399require TkChange; 400 401# compatibility includes 402if ($Tk::VERSION < 800) { 403 print STDERR Mfmt("Die Tk-Version ist veraltet (%s). M�glicherweise ist 404BBBike trotzdem benutzbar. Empfohlen wird ein Upgrade auf Version 804.027 oder 405besser.\n", $Tk::VERSION); 406} 407 408if ($Tk::VERSION <= 402.004) { 409 require TkCompat; 410} 411 412if ($os eq 'unix' && $Tk::VERSION >= 804.027001) { 413 require Tk::MsgBox; 414 import Tk::MsgBox 'as_default'; 415} 416 417# OS compat 418if ($os eq 'win') { 419 require Win32Util; 420} elsif ($^O eq 'darwin') { 421 require MacOSXUtil; 422} 423 424my $terminal_encoding; 425if ($os eq 'win') { 426 require WinCompat; 427 # XXX This encoding is maybe valid for Win98 (some?) command.com, what about other Windows? 428 # XXX Unfortunately using encoding on STDERR 429 # creates a segfault with ActivePerl Build 811 + Win98, so it's disabled... 430 #$terminal_encoding = "cp850"; 431} else { 432 local $^W = undef; 433 if ("$ENV{LANG}$ENV{LC_ALL}" =~ /utf-?8/i) { 434 $terminal_encoding = "utf8"; 435 } 436} 437if ($terminal_encoding && $] >= 5.008) { 438 eval ' 439 binmode STDOUT, ":encoding($terminal_encoding)"; 440 binmode STDERR, ":encoding($terminal_encoding)"; 441 '; warn $@ if $@; 442} 443 444# enable DnD 445use Tk::DropSite; 446 447# Var section: map scales and orientation 448set_landscape(); 449$scale_coeff = 1; 450$small_scale = 0.0625; # map scale for overview window (region mode) 451$medium_scale = 0.13; # map scale for overview window (city/Berlin mode) 452$small_scale_edit = 0.01; # dasselbe f�r den Edit-Mode XXX remove? 453$medium_scale_edit = 0.02; 454set_canvas_scale(DEFAULT_SCALE); # sets $scale 455Karte::preload('Standard'); 456my $init_scale_massstab; # in 1:x form 457$bbbike_route_ext = 'bbr'; 458$map_bg = 'grey85'; 459use vars qw($balloon_info_from_all_tags_closeenough); 460$balloon_info_from_all_tags_closeenough = 3; # was 5, then 4 461 462# Var section: street and point attributes 463$init_str_draw{'s'} = 1; # draw streets by default 464for (qw(s l r b u w f v e z g gP gD gBO sBAB fz wr)) { $p_sub_draw{"pp-$_"} = 1} # this list should cover most keys of %str_file (but not the dependent ones like "comm" or "qs") 465$init_p_draw{'lsa'} = 1; 466$p_far_away{'o'} = 0; 467$str_restrict{'s'} = {qw(BAB 0 B 1 HH 1 H 1 NH 1 N 1 NN 1 Pl 0 Br 0)}; # Pl = places, Br = bridges 468# NOTE: This is misused for getting all valid RBahn categories: 469$str_restrict{'r'} = {qw(RA 1 RB 1 RC 1 R 1 R0 0 RBau 0 RG 1 RP 0)}; 470$str_restrict{'b'} = {qw(S 1 SA 1 SB 1 SC 1 S0 0 SBau 0 SBetrieb 0)}; 471$str_restrict{'u'} = {qw(U 1 UA 1 UB 1 U0 0 UBau 0 UBetrieb 0)}; 472$str_restrict{'qs'} = {qw(Q0 0 Q1 1 Q2 1 Q3 1)}; 473$str_restrict{'ql'} = {qw(Q0 0 Q1 1 Q2 1 Q3 1)}; 474$str_restrict{'hs'} = {qw(q0 0 q1 1 q2 1 q3 1 q4 1)}; 475$str_restrict{'hl'} = {qw(q0 0 q1 1 q2 1 q3 1 q4 1)}; 476$str_ignore{'temp_sperre_s'} = {0 => 1, 1 => 1, 2 => 1, 3 => 1}; # XXX BNP auch? 477# Should maybe go to Strassen::Cat? 478$tunnel_qr = qr{^_?Tu_?$}; 479$roundabout_qr = qr{^(Mini)?Roundabout$}; 480# no $cat_rueck handling here 481$complex_IMG_qr = qr/^IMG:([^|]+)(?:\|ANCHOR:([^|]+))?$/; 482$viewangle_qr = qr{^View:([-+]?\d+):([-+]?\d+)}; # XXX duplicated in Strassen::Cat 483 484# do not draw Steigung and Gef�lle at the same time: 485$str_ignore{'comm'} = {'Gf' => 1}; # XXX with ";"??? 486require Radwege; 487foreach (@Radwege::category_order) { 488 $str_restrict{'rw'}->{$Radwege::category_code{$_}} = 1 489 if defined $Radwege::category_code{$_}; 490} 491$str_nr_draw{'comm-route'} = 1; 492$str_nr_draw{'sBAB'} = 1; # XXX sollte vielleicht umschaltbar sein? 493# minimum width for "two-track" effect 494$sBAB_two_track_width = 3; 495 496$do_iconframe = 1; 497$do_route_strnames = 0 if !defined $do_route_strnames; 498$do_route_strnames_km = 0 if !defined $do_route_strnames_km; 499$do_route_strnames_compact = 0 if !defined $do_route_strnames_compact; 500$do_route_strnames_comments = 1 if !defined $do_route_strnames_comments; 501$net_type = "s"; 502$no_make_net = 0; 503$str_far_away{'w'} = 0; 504$orte_label_size = 1; 505use constant MIN_ORT_CAT => 0; 506use constant MAX_ORT_CAT => 6; 507$str_far_away{'l'} = 0; 508$show_overview_mode = "city"; 509$show_overview = $show_strlist = 0; 510$show_calories = 0; 511$use_hoehe = 1; # XXX kann im Programm nicht gesetzt werden 512$steigung_optimierung = 0; 513$green_optimization = 0; 514$special_vehicle_rb = 'normal'; 515$grade_minimum_short_length = 100; # 100m gilt als kurz f�r grademinimumshort 516$use_legend = $use_legend_right = 0; 517$use_faehre = 0; 518$sperre{'einbahn'} = 1; 519$sperre{'einbahn-strict'} = 0; 520$sperre{'sperre'} = 1; 521$sperre{'wegfuehrung'} = 1; 522$sperre{'Q3'} = 0; 523$sperre_file = "gesperrt"; 524# immediate_replot: 0 = none, 1 = immediate, 2 = deferred 525my($immediate_replot, $immediate_recalc) = (1, 1); 526$auto_visible = 1; 527%tag_visibility = 528 ('p-hoehe' => 1, 529 'str-s-NN' => 0.5, 530 'str-s-N' => 0.5, 531 'p-lsa' => 0.5, 532 'p-o-0' => 0.375, 533 'p-o-1' => 0.25, 534 'str-s-H' => 0.125, 535 'p-o-2' => 0.125, 536 ); 537$map_draw = 0; 538$map_default_type = 'berlinmap'; 539$use_map_fallback = 1; 540$map_surround = 0; 541$dont_delete_map = 1; 542$use_current_coord_prefix = 0; 543$coord_prefix = undef; 544$coordlist_lbox_nl = ""; 545$min_cache_decider_time = 0.500; # 500ms, dann wird gecached 546$steady_mark = 0; 547$lowmem = 0; 548$use_logo = 1 if !defined $use_logo; 549$center_loaded_route = 0; 550$zoom_loaded_route = 1; 551$zoom_new_route = 0; 552$zoom_new_route_chooseort = 1; 553$special_edit = ''; 554$map_mode = MM_SEARCH; 555%b2_mode_desc = (B2M_NONE, M"Nichts", 556 B2M_SCAN, M"Scanning", 557 B2M_FASTSCAN, M"Fast Scanning", 558 B2M_AUTOSCROLL, M"Autoscrolling", 559 B2M_DELLAST, M"Letzten Punkt l�schen", 560 ); 561# Default ist rot, weil das Orange von power oder wind schlecht zu erkennen ist 562$mark_color = 'red'; # Farbe der Markierung in mark_street et al. 563$mark_color_overview = 'blue'; # better than red because it does not conflict with Bundesstra�en 564$gps_waypoints = 50; 565$gps_waypointlength = 10; 566$gps_waypointcharset = 'ascii'; 567$gps_needuniqueroutenumber = 0; 568 569### Fonts 570$standard_height = 12; 571set_sans_serif_font_family(); 572 573### Images 574@image_type_order = ('png', # best quality 575 'jpg', # 24bit, good quality XXX what about non-real world photo images? 576 'xpm', # small memory size (8bit pixmaps) 577 'gif', 578 ); 579 580################################################################### 581$really_no_www = $os eq 'win'; # Trumpet und Win32Sock h�ngen zu lange, wenn es keine Verbindung gibt XXX aber moderne Windows nicht mehr, oder? 582$no_map = !$devel_host && (!defined $ENV{USER} || $ENV{USER} !~ /^(eserte|rezic|srezic|slavenr)$/); 583$abbiege_optimierung = 0; 584# Verlust in Metern beim Linksabbiegen ohne Ampel 585# XXXXX und beim Geradeausfahren?????? 586$abbiege_penalty = { 'H' => 70, # entspricht ca. 10s bei 25km/h 587 'HH' => 140, # entspricht ca. 20s bei 25km/h 588 'BAB' => 140, # h�h? f�r Radfahrer? 589 'B' => 140, 590 }; 591$lost_strecke_per_ampel = 50; # verlorene Strecke pro Ampel in m # XXX F ...? 592%lost_time_per_ampel = ('X' => 15, 593 'F' => 5, 594 # B? 595 ); # verlorene Zeit pro Ampel in s 596$average_v = 0; 597 598$radwege_optimierung = 0; 599for(0..$#Radwege::category_order, "") { 600 $radwege_speed{"RW$_"} = 100; 601} 602 603@strcat_order = qw(B HH H NH N NN); 604if (0) { # not enabled by default 605 unshift @strcat_order, "BAB"; 606} 607 608$steigung_penalty = {}; 609$strecke = 0; 610$dim_color = '#999999'; 611$unit_s = 'km'; 612$next_is_undo = 0; 613# kontrolliert das Zeichnen der Start/Zielflagge: 614@do_flag{qw(start via ziel)} = (1, 1, 1); 615# $in_search: wahr, wenn gerade gesucht wird 616 617use enum qw(:SRP_ COORD TYPE); 618 619$aufschlag = 1; # XXX ??? 620 621# Do as early as possible to avoid warnings: 622if (!$ENV{HOME} || !-d $ENV{HOME}) { # z.B. unter Win32 623 $ENV{HOME} = $FindBin::RealBin; 624} 625 626# Weather variables section 627$wetter_force_update = 1 if !defined $wetter_force_update; 628$wetter_route_update = 0 if !defined $wetter_route_update; 629$wetter_station = 'uptodate' if !defined $wetter_station; 630@wetter_dir = ("$ENV{HOME}/doc/met", "/home/e/eserte/doc/met"); 631%wetter_zuordnung = 632 ('dahlem1' => 'wetter-full', 633 'dahlem2' => 'wetter', 634 #'tempelhof' => 'wetter-tempelhof', 635 ); 636%wetter_name = 637 ('dahlem1' => M"Dahlem (FU, lang)", 638 'dahlem2' => M"Dahlem (FU, kurz)", 639 #'tempelhof' => M"Tempelhof (DWD)", 640 ); 641%wetter_full = ('dahlem1' => 1); 642$temperature = 20; # degrees Celsius 643BBBikeCalc::init_wind(); 644 645use enum qw(:WIND_COLOR_ RED GREEN BLUE NAME); 646 647%wind_colors = (-2 => [qw(255 0 0 red)], 648 -1 => [qw(255 165 0 orange)], 649 0 => [qw(255 215 0 gold)], 650 1 => [qw(154 205 50 YellowGreen)], 651 2 => [qw(105 139 105 DarkSeaGreen4)], 652 ); 653 654## DEBUG_BEGIN 655#BEGIN{mymstat("use vars f�r postscript...");} 656## DEBUG_END 657### Postscript 658$ps_color = 'color'; 659$ps_rotate = 1; 660$ps_scale_a4 = 1; 661$ps_fixed_font = "Courier7"; 662$nr = -1; # number of points in route (XXX correct???) 663 664# User directories (~/.bbbike, route directory, cache) 665my $home = $ENV{HOME}; 666if ($os eq 'win') { 667 $home = Win32Util::get_user_folder(); 668 if (-d $home) { 669 $bbbike_configdir = catfile($home, "BBBike"); 670 } 671} 672if (!defined $bbbike_configdir) { 673 $bbbike_configdir = defined $home ? catfile($home, ".bbbike") : "/bbbike.cfg"; 674} 675if (!-d $bbbike_configdir) { 676 mkdir $bbbike_configdir, 0700; 677} 678if (-d $bbbike_configdir) { 679 $bbbike_routedir = catfile($bbbike_configdir, "route"); 680 if (!-d $bbbike_routedir) { 681 mkdir $bbbike_routedir, 0700; 682 } 683} 684$oldpath = $bbbike_routedir; 685$save2_path = $home; 686 687{ 688 # Hopefully robust determination of temporary directory 689 die "\$bbbike_configdir is not set" if !defined $bbbike_configdir; 690 my $cachedir = catfile($bbbike_configdir, "cache"); 691 if (!-d $cachedir) { 692 mkdir $cachedir, 0700; 693 } 694 $cache_root = (-d $cachedir && -w $cachedir 695 ? $cachedir 696 : $tmpdir); 697 $Karte::cache_root = $cache_root; 698 $Strassen::Util::cachedir = $cache_root; 699} 700 701{ 702 for my $_testdir ('__SPEC__', 703 $ENV{TMPDIR}, 704 ($^O eq 'MSWin32' ? ($ENV{TEMP}, $ENV{TMP}) : ()), 705 "/tmp", 706 "/temp", 707 '__CONFIG__', 708 ) { 709 my $testdir = $_testdir; 710 next if !defined $testdir; 711 if ($_testdir eq '__SPEC__') { 712 $testdir = eval { require File::Spec; File::Spec->tmpdir }; 713 next if !defined $testdir; 714 } elsif ($_testdir eq '__CONFIG__') { 715 $testdir = catfile($bbbike_configdir, "tmp"); 716 if (!-d $testdir) { 717 mkdir $testdir, 0700; 718 } 719 } 720 721 if (-d $testdir && -w $testdir) { 722 $tmpdir = $testdir; 723 last; 724 } 725 } 726 if (!defined $tmpdir) { 727 $tmpdir = "/tmp"; 728 print STDERR M("Achtung: es konnte kein schreibbares tempor�res Verzeichnis gefunden werden. Unter Umst�nden sind einige Operationen nicht m�glich.") . "\n"; 729 } 730} 731 732# XXX $do_wwwmap stuff is sort-of obsolete. Remove completely? 733Karte::preload('Berlinmap2000'); 734$do_wwwmap = (! $Karte::Berlinmap2000::obj || 735 ! -e $Karte::Berlinmap2000::obj->fs_dir); 736if ($devel_host) { 737 $Karte::cache_root = "/usr/www/berlin"; 738} 739 740# Hook init 741foreach (qw(before_plot after_plot new_route del_route after_resize 742 after_new_layer after_delete_layer 743 after_change_visibility after_change_stacking 744 delete_background_images 745 )) { 746 new Hooks $_; 747} 748 749eval { local $SIG{'__DIE__'}; 750 do "$FindBin::RealBin/$progname" . "_0.config" }; 751 752## DEBUG_BEGIN 753#BEGIN{mymstat("before getopt BEGIN");} mymstat("before getopt"); 754## DEBUG_END 755 756handle_options(); 757 758# at this point the $devel_host setting is valid (_set_public was maybe called) 759if ($devel_host && !$public && !grep { "danger" eq $_ } @Strassen::Dataset::comments_types) { 760 push @Strassen::Dataset::comments_types, "danger"; 761} 762@comments_types = @Strassen::Dataset::comments_types; 763 764if ($lowmem) { 765 @image_type_order = ('xpm', 'gif', 'jpg', 'png'); 766} 767 768## DEBUG_BEGIN 769#mymstat("after getopt processing"); 770## DEBUG_END 771 772use vars qw($city_obj $dataset_title); 773if (!defined $city && !defined $datadir) { 774 $city = "Berlin"; 775 $country = "DE"; 776} 777if (defined $city) { 778 require Geography; 779 $city_obj = Geography->new($city, $country); 780 if (!$city_obj) { 781 die Mfmt("Kann keine passende Datei f�r Stadt=%s und Land=%s finden", 782 $city, (defined $country ? $country : M("(unbestimmt)"))); 783 } 784 set_datadir($city_obj->datadir, -clearold => 1); 785 %global_search_args = $city_obj->search_args; 786 if ($city eq "Berlin") { 787 $no_original_datadir = 0; # XXX Was bedeutet das genau? 788 $dataset_title = undef; 789 } else { 790 $no_original_datadir = 1; # XXX Was bedeutet das genau? 791 $dataset_title = $city . " " . $country; 792 } 793 if ($city_obj->scrollregion) { 794 @scrollregion = $city_obj->scrollregion; 795 $normal_scrollregion = $scrollregion[2]-$scrollregion[0]; 796 for (@scrollregion) { $_ *= $scale }; 797 } 798} elsif ($datadir) { 799 set_datadir($datadir, -clearold => 1); 800 $no_original_datadir = 1; 801 $dataset_title = $city_obj && $city_obj->{dataset_title} ? $city_obj->{dataset_title} : basename($datadir); 802} 803if (!$city_obj) { 804 require Geography::Base; 805 $city_obj = Geography::Base->new; 806 warn "Fallback to unspecified city object...\n"; 807} 808 809if ($city_obj->can("skip_features")) { 810 %skip_features = map{($_,1)} $city_obj->skip_features; 811} 812# XXX nicer solution? 813if ($city_obj->is_osm_source) { 814 $sBAB_two_track_width = 9999; # effectively turning off 815} 816 817# define_item_attribs should be called after determining the $city 818define_item_attribs(); 819generate_plot_functions(); 820 821if (!@scrollregion) { 822 my $init_scrollregion = $Karte::Standard::init_scrollregion; 823 $normal_scrollregion = $init_scrollregion*$scale; 824 @scrollregion = ((-$normal_scrollregion) x 2, 825 ($normal_scrollregion) x 2); 826} 827 828# XXX Henne-und-Ei-Problem: ich w�rde gerne Plotting-Defaults anhand der 829# -city-Option setzen (z.B. Zeichnen der Landstra�en f�r OR). Problem: 830# das initiale Setzen von %init_str geschieht auch w�hrend handle_options 831# Ich br�uchte also eine Art pre_handle_options, um erst einmal die 832# -city-Option herauszufischen und dann den Rest handhaben... 833 834if ($environment ne "normal") { 835 eval { local $SIG{'__DIE__'}; 836 require $progname . "_" . $environment . ".config" }; 837} 838 839## DEBUG_BEGIN 840#mymstat("before advanced"); 841## DEBUG_END 842if ($advanced) { 843 $^W = 1; 844 Karte::preload(':all'); 845 require BBBikeAdvanced; 846} 847 848# XXX The MM_DRAG (move) button could be removed completely some day. 849use vars qw($MM_DRAG_IS_OBSOLETE);$MM_DRAG_IS_OBSOLETE = 1; 850 851$coord_system_obj = $Karte::Standard::obj; 852$coord_system = $coord_system_obj->token; 853 854if ($verbose) { 855 set_verbose(); 856} 857 858if ($proxy) { 859 $wettermeldung2::proxy = $proxy; 860} 861 862if ($do_www) { 863 $wetter_source{'www'} = 1; 864} 865if (wetter_dir_exists() and !$public) { 866 $wetter_source{'db'} = 1; 867} 868if ($devel_host and !$public) { 869 $wetter_source{'local'} = 1; 870} 871# XXX ja? 872# �berpr�fen ... auf win32 wird trotz do_www=0 trotzdem geladen?! 873if (!grep($_, values %wetter_source) and $do_www and !$really_no_www) { 874 $wetter_source{'www'} = 1; 875} 876 877# XXX DEL: all occurences of $XXX_use_old_R_symbol 878use vars qw($XXX_use_old_R_symbol); 879$XXX_use_old_R_symbol = 0; # !$devel_host; # Old ugly R symbol or "eisenbahn" 880 881if ($net_type ne 's' && $coloring eq 'wind') { 882 $coloring = 'black'; 883} 884reset_wind(); 885## DEBUG_BEGIN 886#mymstat("before update_weather"); 887## DEBUG_END 888update_weather(1) if $want_wind; 889## DEBUG_BEGIN 890#mymstat("after update_weather"); 891## DEBUG_END 892$wetter_route_update = 1; 893 894# Always use Bikepower (e.g. mandatory for Steigungsoptimierung) 895$bikepwr = 1; 896if ($bikepwr) { 897 eval { 898 require BikePower; 899 }; 900 if ($@) { 901 status_message(Mfmt("Kann BikePower nicht laden: %s", $@), 'err'); 902 $bikepwr = 0; 903 } else { 904 if ($verbose && $BikePower::has_xs) { 905 print STDERR M"Verwende die XS version von BikePower\n"; 906 } 907 $bp_obj = new BikePower; 908 $bp_obj->given('P'); 909 $bp_obj->temperature($temperature); 910 911 set_corresponding_power(); 912 } 913} 914if (!@power) { 915 @power = (50, 100); 916} 917 918TRY_SPEED_POWER_REFERENCE_STRING: { 919 $active_speed_power{Type} = 'speed'; 920 $active_speed_power{Index} = 0; 921 if (defined $speed_power_reference_string) { 922 my($type, $val) = split /:/, $speed_power_reference_string; 923 if ($type =~ /^(speed|power)$/) { 924 my $i = 0; 925 for ($type eq 'speed' ? @speed : @power) { 926 if ($val eq $_) { 927 $active_speed_power{Index} = $i; 928 $active_speed_power{Type} = $type; 929 last TRY_SPEED_POWER_REFERENCE_STRING; 930 } 931 $i++; 932 } 933 print STDERR "Referenzgeschwidigkeit/-leistung $type $val wird ignoriert\n"; 934 } else { 935 print STDERR "Die Option -reference sollte im Format type:value sein, wobei type entweder speed oder power ist und value die entsprechende Geschwindigkeit in km/h oder Leistung in W\n"; 936 } 937 } 938} 939 940mk_speed_txt(); 941for(my $i = 0; $i <= $#speed; $i++) { 942 $ampel_count->{"speed"}[$i] = 1; 943 $kopfstein_count->{"speed"}[$i] = 1; 944} 945for(my $i = 0; $i <= $#power; $i++) { 946 $ampel_count->{"power"}[$i] = 1; 947 $kopfstein_count->{"power"}[$i] = 1; 948} 949 950eval { 951 set_coord_output_sub(); 952}; warn __LINE__ . ": $@" if $@; 953 954change_net_type(); 955 956if ($do_wwwmap && $devel_host) { 957 $map_default_type = 'b2004'; 958} 959 960if ($all_outline) { 961 $str_outline{'s'} = 962 $str_outline{'l'} = 963 $str_outline{'w'} = 964 $str_outline{'i'} = 1; 965} 966 967if (defined $init_scope) { 968 if ($init_scope eq 'city') { city_settings() } 969 elsif ($init_scope eq 'region') { region_settings() } 970 elsif ($init_scope eq 'jwd') { jwd_settings() } 971} 972 973if ($visual) { 974 push(@extra_args, -visual => $visual); 975} 976 977if ($Tk::VERSION < 803 || $Tk::VERSION >= 804.025) { 978 eval { require Tk::UnderlineAll }; 979 warn __LINE__ . ": $@" if $@ && $verbose; 980} 981 982eval { local $SIG{'__DIE__'}; 983 do "$FindBin::RealBin/$progname" . "_1.config" }; 984 985## DEBUG_BEGIN 986#BEGIN{mymstat("irgendwo in der mitte BEGIN");} mymstat("irgendwo in der mitte"); 987## DEBUG_END 988 989if (!defined $top) { 990 $top = MainWindow->new(@extra_args); 991 $top->{initial_iconic} = $top->state eq 'iconic'; 992 993 $top->scaling($scaling) if defined $scaling && $scaling ne ""; 994 995 # Es gibt gute Gr�nde, f�r CloseMainWin kein Escape zu nehmen 996 # (damit k�nnen Vorg�nge abgebrochen werden). Verwendung von C-q, 997 # weil das mittlerweile quasi-Standard (Gtk, Qt/KDE, Windows) ist. 998 $top->eventAdd(qw[<<CloseMainWin>> <Control-c> <Control-q>]); 999 $top->eventAdd(qw[<<CloseWin>> <Control-c> <Escape>]); 1000 1001 if ($os eq 'win') { # vorerst, Windows kann keine tearoffs 1002 $top->optionAdd("*tearOff", "false", "startupFile"); 1003 } 1004 if ($os ne 'win') { # use standard bg color on Windows 1005 for (qw(background highlightBackground)) { 1006 $top->optionAdd("*$_", 'grey80', 'startupFile'); 1007 } 1008 # Workaround for a KDE 3.x problem: KDE sets background, but not 1009 # highlightBackground options which looks quite ugly. 1010 my $bg = $top->optionGet("background", "Background"); 1011 if ($top->optionGet("highlightBackground", "HighlightBackground") ne $bg) { 1012 $top->optionAdd("*highlightBackground", $bg, 'interactive'); 1013 } 1014 # Unter Windows sollten Balloons eigentlich -bg => white sein XXX 1015 for (qw(Balloon CanvasBalloon)) { 1016 $top->optionAdd("*$_.background", '#C0C080', 'startupFile'); 1017 } 1018 for (qw(Scale Scrollbar)) { 1019 $top->optionAdd("*$_.troughcolor", "grey95", "startupFile"); 1020 } 1021 } 1022 # This is the list of widgets with some "action" area (editable or 1023 # selectable). It seems that the consensus in the GUI world is to 1024 # have this widgets in a brighter color (like Tix, Gtk, Windows...). 1025 # Do it so. 1026 # Browse is for Tk::HistEntry::Browse 1027 for (qw(Browse Entry NumEntry Date*NumEntryPlain PathEntry 1028 Listbox KListbox K2Listbox 1029 TixHList HList Text ROText BrowseEntry.LabEntry SimpleHistEntry 1030 ListboxSearchAnything 1031 )) { 1032 if ($os eq 'win') { 1033 $top->optionAdd("*$_.background", "SystemWindow", "startupFile"); 1034 } else { 1035 $top->optionAdd("*$_.background", "grey95", "startupFile"); 1036 } 1037 } 1038 # Introduce a www browser-like cursor feeling: 1039 for (qw(Button Checkbutton Radiobutton Menubutton 1040 FlatCheckbox FlatRadiobutton FireButton)) { 1041 $top->optionAdd("*$_.cursor", "hand2", "startupFile"); 1042 } 1043 1044 if (0) { # ... naja, m�sste ein Designer ran ... au�erdem with -tile nicht mehr unterst�tzt (?), und mit Windows ging's noch nie 1045 my $bg = $top->Photo(-file => Tk::findINC("images/bg.gif")); 1046 for (qw(Toplevel Label Button Checkbutton Radiobutton FlatBut 1047 FlatCheckbox FlatRadiobutton FireButton Menubutton Frame Pane), 1048 "Bbbike Chooser", "Bbbike Copyright", "Bbbike Window", 1049 "Bbbike Extended Chooser", "Bbbike Overview", 1050 "Bbbike Routeinfo") { 1051 $top->optionAdd("*$_.tile" => $bg) if $bg; 1052 } 1053 $top->optionAdd("*highlightBackground" => "white"); 1054 } 1055} 1056 1057## DEBUG_BEGIN 1058#BEGIN{mymstat("after basic MainWindow setup BEGIN");} mymstat("after basic MainWindow setup"); 1059## DEBUG_END 1060 1061# KDE initialisation 1062if ($run_under_kde) { 1063 eval { 1064 require KDEUtil; 1065 if ($kde = new KDEUtil -top => $top, -checkrunning => 1) { 1066 my $kde_focus_policy = 1067 KDEUtil::WM::get_config($kde, 'General', 'FocusPolicy'); 1068 local $^W = 0; 1069 $focus_policy = ($kde_focus_policy eq 'ClickToFocus' 1070 ? 'click' 1071 : 'follow'); 1072 $kde->kde_config_for_tk; 1073 } 1074 }; 1075 warn __LINE__ . ": $@" if $@; # XXX and $verbose 1076} 1077 1078## DEBUG_BEGIN 1079#BEGIN{mymstat("after KDE initialisation");} mymstat("after KDE initialisation"); 1080## DEBUG_END 1081 1082if (!defined $focus_policy) { 1083 if ($os eq 'unix') { 1084 #XXX $focus_policy = 'follow'; 1085 $focus_policy = 'click'; 1086 } else { 1087 $focus_policy = 'click'; 1088 } 1089} 1090 1091if ($focus_policy eq 'follow') { 1092 @popup_style = ('-popover', 'cursor'); 1093 # This seems to be a good idea for all platforms, but 1094 # is dangerous where focus also means "raise" and the 1095 # toplevel is not marked as transient. Therefore 1096 # first check if this work OK and maybe always enable 1097 # in BBBike 3.16 XXX 1098 # 1099 # Another problem, the reason why I disabled this for now: if 1100 # the search window is redisplayed by hitting the "/" 1101 # key, then the focus is not set to the search field. 1102 # 1103 #$top->focusFollowsMouse; 1104} else { 1105 @popup_style = (); 1106} 1107 1108# erst *nach* new MainWindow aufrufen (wegen Tk::CmdLine) 1109if (@ARGV) { 1110 $preload_file = $ARGV[0]; 1111} 1112 1113# Die folgende Reihenfolge ist wichtig einzuhalten: 1114# * Geometry ermitteln und in @want_extends ablegen, aber noch nicht setzen 1115# (set_default_geometry, geometry_dependent_settings) 1116# * Zeichens�tze ermitteln und Default einstellen (set_fonts) 1117# * EmptyMenubar zeichnen 1118# * Geometry setzen 1119 1120use enum qw(:GEOMETRY_ X Y WIDTH HEIGHT); 1121 1122# Geometry 1123set_default_geometry(); 1124geometry_dependent_settings(); 1125 1126# dots per inch und mm, must be called before set_fonts 1127$top_dpmm = $top->screenwidth/$top->screenmmwidth; 1128$top_dpi = $top_dpmm*25.4; 1129$ps_image_res = int($top_dpi) . "x" . int($top_dpi); 1130 1131## DEBUG_BEGIN 1132#BEGIN{mymstat("before setfonts BEGIN");} mymstat("before setfonts"); 1133## DEBUG_END 1134 1135# Zeichens�tze 1136set_fonts(); 1137 1138## DEBUG_BEGIN 1139#BEGIN{mymstat("after setfonts BEGIN");} mymstat("after setfonts"); 1140## DEBUG_END 1141 1142if ($Tk::VERSION < 800) { 1143 $standard_menubar = 0; 1144} 1145if ($standard_menubar && !$top->cget(-menu)) { 1146 require BBBikeMenubar; 1147 BBBike::Menubar::EmptyMenubar(); # Platz reservieren ... 1148 # Tk feature: menu bar is not counted to geometry 1149 my $menu_height; 1150 if ($os eq 'unix') { 1151 $top->withdraw; 1152 $top->update; 1153 $menu_height = ($top->wrapper)[1]; 1154 } else { 1155 # wrapper[1] is not implemented on Windows ... guess menu height 1156 $menu_height = 20; 1157 } 1158 if ($want_extends[GEOMETRY_HEIGHT] =~ /^-/) { 1159 $want_extends[GEOMETRY_HEIGHT] += $menu_height; 1160 } else { 1161 $want_extends[GEOMETRY_HEIGHT] -= $menu_height; 1162 } 1163} 1164 1165if (@want_extends) { 1166 if (($want_extends[GEOMETRY_WIDTH] < 30 && $want_extends[GEOMETRY_WIDTH] !~ /^-/) || 1167 ($want_extends[GEOMETRY_HEIGHT] < 20 && $want_extends[GEOMETRY_HEIGHT] !~ /^-/) || 1168 $want_extends[GEOMETRY_X] < 0 || 1169 $want_extends[GEOMETRY_Y] < 0) { 1170 print STDERR M("Die Fenstergr��e wird wegen ung�ltiger Werte nicht gesetzt: ") 1171 . join(", ", @want_extends), "\n"; 1172 } else { 1173 geometry($top, @want_extends); 1174 @want_extends = (); 1175 } 1176} 1177 1178if (defined $init_scale_massstab) { 1179 if ($init_scale_massstab =~ m{^1:(\d+)$}) { 1180 my $nenner = $1; 1181 my $nenner_now = calc_mapscale_nenner(); 1182 # to the old $scale form: 1183 $init_scale_massstab = ($scale*$nenner_now)/$nenner; 1184 } 1185 1186 if ($init_scale_massstab > 0) { 1187 my $oldscale = $scale; 1188 set_canvas_scale($init_scale_massstab); 1189 my $change_scale_factor = $scale/$oldscale; 1190 foreach (@scrollregion) { 1191 $_ *= $change_scale_factor; 1192 } 1193 } else { 1194 print STDERR "Ung�ltiger Skalierungswert <$init_scale_massstab> wird ignoriert\n"; 1195 } 1196} 1197 1198$top->title("$progname $VERSION" . 1199 ($dataset_title ? " [$dataset_title]" : "") 1200 ); 1201 1202my $has_icon = 0; 1203my $set_toplevel_icon; 1204$srtbike_photo = load_photo($top, 'srtbike_solid'); 1205$srtbike16_icon = load_photo($top, 'srtbike16'); # used in info window 1206if ($os eq 'win' || $^O eq 'cygwin') { 1207 # Prefer .ico 1208 my $icon; 1209 if ($Tk::VERSION >= 804.027 and 1210 $icon = $FindBin::RealBin.'/images/srtbike.ico' and 1211 -r $icon and 1212 eval { 1213 $top->iconbitmap($icon); 1214 1; 1215 }) { 1216 $has_icon = 1; 1217 $set_toplevel_icon = sub { 1218 my $self = shift; 1219 eval { 1220 $self->iconbitmap($icon); 1221 }; 1222 }; 1223 } else { 1224 # srtbike32.* looks broken on Win98 and Vista, 1225 # and srtbike16.* looks broken on WinXP and Vista 1226 if ($ENV{OS} && $ENV{OS} eq 'Windows_NT') { # this seems to be the case for XP 1227 $srtbike_icon = load_photo($top, 'srtbike32'); 1228 } else { 1229 $srtbike_icon = $srtbike16_icon; 1230 } 1231 } 1232} else { 1233 # 16x16 is the preferred size for mini-icons in KDE 1234 # works also for twm (however, a little bit tiny) 1235 $srtbike_icon = $srtbike16_icon; 1236 if ($srtbike_icon) { 1237 $top->iconmask('@' . $FindBin::RealBin . '/images/srtbike16_mask.xbm'); 1238 } 1239} 1240 1241if (!$has_icon) { 1242 # In ->Icon wird auch ein ->update durchgef�hrt: 1243 # XXX Unter Unix vielleicht darauf verzichten und iconimage stattdessen verwenden? 1244 # XXX Also set icon according to freedesktop specs. 1245 if (defined $srtbike_icon) { 1246 $top->Icon(-image => $srtbike_icon); 1247 $set_toplevel_icon = sub { 1248 my $self = shift; 1249 eval { 1250 $self->iconimage($main::srtbike_icon); 1251 }; 1252 }; 1253 } 1254} 1255 1256if ($devel_host && $set_toplevel_icon) { 1257 # every toplevel in app should get bbbike icon 1258 require Tk::Toplevel; # make sure it's loaded 1259 package Tk::Toplevel; 1260 *InitObject = *InitObject; # cease warnings 1261 *InitObject = sub { 1262 my($self,$args) = @_; 1263 $self->SUPER::InitObject($args); 1264 # setting icon may fail in other mainwindows 1265 $self->afterIdle(sub { $set_toplevel_icon->($self) }); 1266 }; 1267} 1268 1269{ 1270 # experimental... 1271 my $freedesktop_lib = "$ENV{HOME}/work/Tk-FreeDesktop-Wm/blib/lib"; 1272 if (-d $freedesktop_lib) { 1273 if (!eval { 1274 local @INC = ($freedesktop_lib, @INC); 1275 require Tk::FreeDesktop::Wm; 1276 my $fd = Tk::FreeDesktop::Wm->new(mw => $top); 1277 $fd->set_wm_icon("$FindBin::RealBin/images/srtbike_mini.xpm"); 1278 1; 1279 }) { 1280 warn "Cannot load Tk::FreeDesktop::Wm ($@), no NET icon support..."; 1281 } 1282 } 1283} 1284 1285if ($splash_screen) { 1286 $splash_screen->Raise; # raise after the first ->update on $top, otherwise on Windows the splash screen will stay obscured by the main window 1287 $splash_screen->Update(0.0, 'raise splash'); 1288} 1289 1290# Define something else on X server bugs (e.g. "projecting") 1291$capstyle_round = "round"; 1292 1293# erst hier ist die @power-Zuweisung abgeschlossen 1294for(my $i=0; $i <= $#power; $i++) { 1295 $bikepwr_time[$i] = 0; 1296 $bikepwr_cal[$i] = 0; 1297} 1298mk_power_txt(); 1299 1300## DEBUG_BEGIN 1301#BEGIN{mymstat("after mk_power_txt BEGIN");} mymstat("after mk_power_txt"); 1302## DEBUG_END 1303 1304# Zeichens�tze f�r Stra�ennamen 1305# Normal 1306if (defined $font_family && $font_family =~ /nimbus/) { 1307 # XXX nimbus is a rather obscure font found in 1308 # /usr/ports/x11-fonts/freefonts --- maybe use another? 1309 # 1310 # somewhere called "nimbus sans" without "l" 1311 $rot_font_sub = sub { "-*-nimbus sans l-medium-r-condensed--0-" . $_[0] 1312 . "-0-0-p-0-iso8859-1"}; 1313} elsif (defined $font_family && $font_family =~ /luxi/) { 1314 # a Type 1 font --- slower and nicer 1315 $rot_font_sub = sub { '-b&h-Luxi Sans-medium-r-normal--0-' . $_[0] . '-0-0-p-0-iso8859-1'}; 1316} 1317if (defined $rot_font_sub && !check_font($rot_font_sub->(120))) { 1318 print STDERR "Der Normalzeichensatz in <$font_family> kann nicht gefunden werden, der Fallback wird verwendet...\n"; 1319 undef $rot_font_sub; 1320} 1321# Fallback to helvetica 1322if (!$rot_font_sub) { 1323 my $font_family = "helvetica"; 1324 $rot_font_sub = sub { "-*-$font_family-medium-r-normal--0-" . $_[0] 1325 . "-0-0-p-0-iso8859-1"}; 1326} 1327# Bold 1328if (defined $font_family && $font_family =~ /nimbus/) { 1329 $rot_bold_font_sub = sub { "-*-nimbus sans l-bold-r-condensed--0-" . $_[0] 1330 . "-0-0-p-0-iso8859-1"}; 1331} elsif (defined $font_family && $font_family =~ /luxi/) { 1332 $rot_bold_font_sub = sub { '-b&h-Luxi Sans-bold-r-normal--0-' . $_[0] . '-0-0-p-0-iso8859-1'}; 1333} 1334if (defined $rot_bold_font_sub && !check_font($rot_bold_font_sub->(120))) { 1335 print STDERR "Der Fettschriftzeichensatz in <$font_family> kann nicht gefunden werden, der Fallback wird verwendet...\n"; 1336 undef $rot_bold_font_sub; 1337} 1338# Fallback to helvetica bold 1339if (!$rot_bold_font_sub) { 1340 my $font_family = "helvetica"; 1341 $rot_bold_font_sub = sub { "-*-$font_family-bold-r-normal--0-" . $_[0] 1342 . "-0-0-p-0-iso8859-1"}; 1343} 1344%category_rot_font = 1345 ('NN' => $rot_font_sub, 1346 'N' => $rot_font_sub, 1347 'NH' => $rot_font_sub, 1348 'H' => $rot_bold_font_sub, 1349 'HH' => $rot_bold_font_sub, 1350 'B' => $rot_bold_font_sub, 1351 'BAB' => $rot_bold_font_sub, 1352 'W' => $rot_bold_font_sub); 1353 1354# According to 1355# http://web.archive.org/web/20020124125029/www.iarchitect.com/color.htm 1356# using colors for dialog buttons is not advised. Well, anyway... 1357$top->optionAdd("*ok*foreground" => 'green4'); 1358$top->optionAdd("*ok*text" => M"OK"); 1359if ($Tk::VERSION >= 800) { 1360 $top->optionAdd("*ok*default" => 'active'); 1361} 1362$top->optionAdd("*apply*foreground" => 'yellow4'); 1363$top->optionAdd("*apply*text" => M"�bernehmen"); 1364$top->optionAdd("*search*foreground" => 'yellow4'); 1365$top->optionAdd("*search*text" => M"Suchen"); 1366# Fix strangely colored Pod menu 1367$top->optionAdd("*pod*search*foreground" => 'black'); 1368$top->optionAdd("*show*foreground" => 'yellow4'); 1369$top->optionAdd("*show*text" => M"Zeigen"); 1370$top->optionAdd("*default*foreground" => 'yellow4'); 1371$top->optionAdd("*default*text" => M"Voreinstellung"); 1372$top->optionAdd("*cancel*foreground" => 'red'); 1373$top->optionAdd("*cancel*text" => M"Abbrechen"); 1374#XXX Experiment for Tk804. Problems too solve: maybe icon too large for small screens/buttons; images should be transparent: {my $p=load_photo($top, "cross", -name => "cross");for(qw(close cancel)) { $top->optionAdd("*$_*compound","left"); $top->optionAdd("*$_*image","cross")}} 1375$top->optionAdd("*close*foreground" => 'red'); 1376$top->optionAdd("*close*text" => M"Schlie�en"); 1377$top->optionAdd("*end*foreground" => 'green4'); 1378$top->optionAdd("*end*text" => M"Schlie�en"); 1379 1380if ($small_icons) { 1381 $top->optionAdd("*Button*borderWidth" => 1); 1382 $top->optionAdd("*Checkbutton*borderWidth" => 1); 1383} 1384 1385$top->optionAdd("*FlatBut*borderWidth" => 0); 1386$top->optionAdd("*FlatBut*padX" => 1); 1387$top->optionAdd("*FlatBut*padY" => 0); 1388 1389$top->optionAdd("*SmallBut*padX" => 1); 1390$top->optionAdd("*SmallBut*padY" => 1); 1391 1392if ($use_logo and (!$splash_screen or !$splash_screen->{Exists})) { 1393 show_logo(); 1394} 1395 1396if ($use_balloon) { 1397 eval { 1398 require Tk::Balloon; 1399 # -balloonposition: Ansonsten kann es bei Buttons vorkommen, dass 1400 # der Balloon Teile der Klickfl�che �berdeckt. 1401 $balloon = $top->Balloon(-balloonposition => "mouse"); 1402 }; 1403} 1404if (!defined $balloon) { 1405 eval q{ 1406 package Tk::FakeBalloon; # AUTOLOAD: ignore 1407 @Tk::FakeBalloon::ISA = qw(Tk::Label); 1408 Construct Tk::Widget "FakeBalloon"; 1409 sub attach {} 1410 sub configure {} 1411 sub IsWidget { 0 } # for Tk::Exists 1412 package main; 1413 $balloon = $top->FakeBalloon; 1414 }; 1415 warn $@ if $@; 1416} 1417 1418## DEBUG_BEGIN 1419#BEGIN{mymstat("after balloon BEGIN");} mymstat("after balloon"); 1420## DEBUG_END 1421 1422# XXX if !perl2exe 1423if (!$lowmem) { 1424 if (eval { require Tk::CanvasBalloon; 1 }) { 1425 $c_balloon = $top->CanvasBalloon(-initwait => $c_balloon_wait, 1426 -show => $use_c_balloon); 1427 } 1428} 1429 1430## DEBUG_BEGIN 1431#BEGIN{mymstat("after canvasballoon BEGIN");} mymstat("after canvasballoon"); 1432## DEBUG_END 1433 1434TRY: { 1435 last TRY unless $use_contexthelp; 1436 if (!eval { 1437 require Tk::ContextHelp; 1438 Tk::ContextHelp->VERSION(0.05); # Win32 check 1439 }) { 1440 $use_contexthelp = 0; 1441 last TRY; 1442 } 1443 $ch = $top->ContextHelp('-podfile' => "$FindBin::RealBin/$FindBin::Script" . ".pod"); 1444} 1445if (!defined $ch) { 1446 eval q{ 1447 package Tk::ContextHelp; # AUTOLOAD: ignore 1448 sub attach {} 1449 sub activate {} 1450 sub HelpButton { shift; shift->Label(-padx => 0, -pady => 0) } 1451 package main; 1452 $ch = bless {}, "Tk::ContextHelp"; 1453 }; 1454} 1455 1456# This is a hack to fix the background color of BrowseEntry's entry 1457# widget. Maybe something similar should go into official BrowseEntry? 1458# However, if this passes a "test phase" it should be available for 1459# all. 1460if ($devel_host) { 1461 require Tk::BrowseEntry; 1462 *Tk::MyBrowseEntry::oldPopulate = \&Tk::BrowseEntry::Populate; 1463 *Tk::BrowseEntry::Populate = sub { 1464 my $w = shift; 1465 Tk::MyBrowseEntry::oldPopulate($w, @_); 1466 $w->ConfigSpecs(-background=>['SELF']); 1467 }; 1468} 1469 1470## DEBUG_BEGIN 1471#BEGIN{mymstat("after contexthelp BEGIN");} mymstat("after contexthelp"); 1472## DEBUG_END 1473 1474$frame = $top->Frame; 1475$frame->pack(-side => "top", -expand => "yes", -fill => "both"); 1476$ctrl_frame = $frame->Frame->pack(-anchor => 'w', -fill => 'x'); 1477 1478## DEBUG_BEGIN 1479#BEGIN{mymstat("before topframe BEGIN");} mymstat("before topframe"); 1480## DEBUG_END 1481 1482##### Topframe ####################################################### 1483 1484$splash_screen->Update(0.1, 'create top') if $splash_screen; 1485 1486$menuarrow_photo = load_photo($top, 'menupfeil'); 1487 1488my $col = 0; 1489use vars qw($top_frame); 1490$top_frame = $ctrl_frame->Frame->pack(-side => 'top', -anchor => 'w', 1491 -fill => 'x'); 1492 1493use vars qw($hslabel_frame $km_frame @speed_frame $wind_frame 1494 @power_frame $percent_frame $temp_frame); 1495 1496$top_frame->gridColumnconfigure(0, -weight => 1, -minsize => 50); 1497for(1..10) { 1498 $top_frame->gridColumnconfigure($_, -weight => 0); 1499} 1500 1501$hslabel_frame = $top_frame->Frame 1502 (-relief => 'raised', -bd => 1); 1503 1504if (!$small_icons) { 1505 $hslabel_frame->Button 1506 (-text => M('Ort/Bahnhof').':', 1507 -class => 'FlatBut', 1508 -highlightthickness => 0, -takefocus => 0, 1509 -command => sub { choose_ort(qw(p o)) }, 1510 )->grid(-row => 0, 1511 -column => 0, 1512 -sticky => 'w'); 1513 $hslabel_frame->Button 1514 (-text => M('Stra�e/Strecke').':', 1515 -class => 'FlatBut', 1516 -highlightthickness => 0, -takefocus => 0, 1517 -command => \&choose_streets, 1518 )->grid(-column => 0, 1519 -row => 1, 1520 -sticky => 'w'); 1521} 1522 1523#XXXXXXXXXXXXXXXXX Ab hier POD attaches Msg-tauglich machen 1524$hslabel_frame->gridColumnconfigure(1, -weight => 1, -minsize => 10); 1525$hs_label = $hslabel_frame->Label 1526 (-textvariable => \$act_value{Haltestelle}, 1527 -fg => $dim_color, 1528 -font => $font{'bold'}, 1529 -anchor => 'w', 1530 )->grid(-column => 1, -row => 0, -sticky => 'w'); 1531$ch->attach($hs_label, -pod => "^\\s*Ort/Haltestelle"); 1532 1533$str_label = $hslabel_frame->Label 1534 (-textvariable => \$act_value{Strasse}, 1535 -fg => $dim_color, 1536 -font => $font{'bold'}, 1537 -anchor => 'nw', 1538 )->grid(-column => 1, -row => 1, -sticky => 'w'); 1539$ch->attach($str_label, -pod => "^Stra�e/Strecke"); 1540 1541$km_frame = $top_frame->Frame(-relief => 'raised', 1542 -bd => 1); 1543my $kmcb = $km_frame->Button 1544 (-textvariable => \$unit_s, 1545 -class => 'FlatBut', 1546 -command => sub { change_unit() }, 1547 )->pack; 1548if ($km_frame->can('UnderlineAll')) { $km_frame->UnderlineAll } 1549 1550$km_frame->Label(-width => 5, 1551 -textvariable => \$act_value{Km}, 1552 -font => $font{'bold'})->pack; 1553$balloon->attach($km_frame, -msg => M"Streckenl�nge"); 1554$ch->attach($km_frame, -pod => "^\\s*km"); 1555 1556$percent_frame = $top_frame->Frame 1557 (-relief => 'raised', -bd => 1); 1558$percent_frame->Label(-text => "%")->pack; 1559$percent_frame->Label(-width => 4, 1560 -textvariable => \$act_value{Percent}, 1561 -font => $font{'bold'})->pack; 1562$balloon->attach($percent_frame, -msg => M"% �ber Luftlinie"); 1563$ch->attach($percent_frame, -pod => "^\\s*%"); 1564 1565$ampel_klein_photo = load_photo($top, 'ampel_klein'); 1566$ampel_klein_grey_photo = load_photo($top, 'ampel_klein_grey'); 1567$kopfstein_klein_photo = load_photo($top, 'kopfstein_klein'); 1568$kopfstein_klein_grey_photo = load_photo($top, 'kopfstein_klein_grey'); 1569$star_photo = load_photo($top, 'star'); 1570$newlayer_photo = load_photo($top, 'newlayer'); 1571 1572for(my $i = 0; $i <= $#speed; $i++) { 1573 my $ii = $i; # f�r das sub 1574 $speed_frame[$i] = $top_frame->Frame 1575 (-relief => 'raised', -bd => 1); 1576 $ch->attach($speed_frame[$i], -pod => "^\\s*km/h"); 1577 my $b = $speed_frame[$i]->Button 1578 (-textvariable => \$speed_txt[$i], 1579 -class => 'FlatBut', 1580 -command => sub { enter_speed($ii) }, 1581 )->grid(-row => 0, -column => 0); 1582 { 1583 my $f = $speed_frame[$i]->Frame->grid(-row => 0, -column => 1);; 1584 $ampel_count_button->{"speed"}[$i] = 1585 $f->Button 1586 (-image => ($ampel_count->{"speed"}[$i] 1587 ? $ampel_klein_photo 1588 : $ampel_klein_grey_photo), 1589 -class => 'FlatBut', 1590 -padx => 1, 1591 -command => sub { change_ampel_count("speed", $ii) }, 1592 )->pack; 1593 $balloon->attach($ampel_count_button->{"speed"}[$i], 1594 -msg => M"Ampeln in Zeitberechnung aufnehmen"); 1595 1596 $kopfstein_count_button->{"speed"}[$i] = 1597 $f->Button 1598 (-image => ($kopfstein_count->{"speed"}[$i] 1599 ? $kopfstein_klein_photo 1600 : $kopfstein_klein_grey_photo), 1601 -class => 'FlatBut', 1602 -padx => 1, 1603 -command => sub { change_kopfstein_count("speed", $ii) }, 1604 )->pack; 1605 $balloon->attach($kopfstein_count_button->{"speed"}[$i], 1606 -msg => M"Langsamfahrstrecken in Zeitberechnung aufnehmen"); 1607 } 1608 my $l = $speed_frame[$i]->Button 1609 (-width => 7, 1610 -class => 'FlatBut', 1611 -command => sub { 1612 require BBBikeAlarm; 1613 BBBikeAlarm::enter_alarm($top, \$act_value{Time}->[$ii], 1614 -location => get_polar_location_of_route_end()); 1615 }, 1616 -textvariable => \$act_value{Time}->[$i], 1617 -font => $font{'bold'}, 1618 )->grid(-row => 1, -column => 0, -columnspan => 2, -sticky => "ew"); 1619 foreach (qw(2 3)) { 1620 $speed_frame[$i]->bind 1621 ("<ButtonPress-$_>" => 1622 sub { change_active_speed_power("speed", $ii) }); 1623 $b->bind("<ButtonPress-$_>" => 1624 sub { change_active_speed_power("speed", $ii) }); 1625 $l->bind("<ButtonPress-$_>" => 1626 sub { change_active_speed_power("speed", $ii) }); 1627 } 1628 enter_leave_bind_for_help($speed_frame[$i], 1629 [M"Geschwindigkeit eingeben", 1630 M"Geschwindigkeit als Voreinstellung festlegen", 1631 M"Geschwindigkeit als Voreinstellung festlegen", 1632 ]); 1633 enter_leave_bind_for_help($l, 1634 [M"Alarm setzen", undef, undef]); 1635 enter_leave_bind_for_help($ampel_count_button->{"speed"}[$i], 1636 [M"Ampeln in Zeitberechnung aufnehmen", "", ""]); 1637 enter_leave_bind_for_help($kopfstein_count_button->{"speed"}[$i], 1638 [M"Langsamfahrstrecken in Zeitberechnung aufnehmen", "", ""]); 1639} 1640 1641if ($bikepwr) { 1642 for(my $i = 0; $i <= $#power; $i++) { 1643 my $ii = $i; 1644 $power_frame[$i] = $top_frame->Frame 1645 (-relief => 'raised', -bd => 1); 1646 $ch->attach($power_frame[$i], -pod => "^\\s*W\$"); 1647 my $b = $power_frame[$i]->Button 1648 (-textvariable => \$power_txt[$i], 1649 -class => 'FlatBut', 1650 -command => sub { enter_power($ii) }, 1651 )->grid(-row => 0, -column => 0); 1652 { 1653 my $f = $power_frame[$i]->Frame->grid(-row => 0, -column => 1);; 1654 $ampel_count_button->{"power"}[$i] = 1655 $f->Button 1656 (-image => ($ampel_count->{"power"}[$i] 1657 ? $ampel_klein_photo 1658 : $ampel_klein_grey_photo), 1659 -class => 'FlatBut', 1660 -padx => 1, 1661 -command => sub { change_ampel_count("power", $ii) }, 1662 )->pack; 1663 $balloon->attach($ampel_count_button->{"power"}[$i], 1664 -msg => M"Ampeln in Zeitberechnung aufnehmen"); 1665 1666if (0) { # XXX activate if implemented in updatekm() 1667 $kopfstein_count_button->{"power"}[$i] = 1668 $f->Button 1669 (-image => ($kopfstein_count->{"power"}[$i] 1670 ? $kopfstein_klein_photo 1671 : $kopfstein_klein_grey_photo), 1672 -class => 'FlatBut', 1673 -padx => 1, 1674 -command => sub { change_kopfstein_count("power", $ii) }, 1675 )->pack; 1676 $balloon->attach($kopfstein_count_button->{"power"}[$i], 1677 -msg => M"Langsamfahrstrecken in Zeitberechnung aufnehmen"); 1678} 1679 } 1680 my $l = $power_frame[$i]->Button 1681 (-width => 7, 1682 -class => 'FlatBut', 1683 -command => sub { 1684 require BBBikeAlarm; 1685 BBBikeAlarm::enter_alarm($top, \$act_value{PowerTime}->[$ii], 1686 -location => get_polar_location_of_route_end()); 1687 }, 1688 -textvariable => \$act_value{PowerTime}->[$i], 1689 -font => $font{'bold'}, 1690 )->grid(-row => 1, -column => 0, -columnspan => 2, -sticky => "ew"); 1691 foreach (qw(2 3)) { 1692 $power_frame[$i]->bind 1693 ("<ButtonPress-$_>" => 1694 sub { change_active_speed_power("power", $ii) }); 1695 $b->bind("<ButtonPress-$_>" => 1696 sub { change_active_speed_power("power", $ii) }); 1697 $l->bind("<ButtonPress-$_>" => 1698 sub { change_active_speed_power("power", $ii) }); 1699 } 1700 enter_leave_bind_for_help($power_frame[$i], 1701 [M"Leistung eingeben", 1702 M"Leistung als Voreinstellung festlegen", 1703 M"Leistung als Voreinstellung festlegen", 1704 ]); 1705 enter_leave_bind_for_help($l, 1706 [M"Alarm setzen", undef, undef]); 1707 # XXX not yet activated 1708 #enter_leave_bind_for_help($ampel_count_button->{"speed"}[$i], 1709 #[M"Ampeln in Zeitberechnung aufnehmen", "", ""]); 1710 #enter_leave_bind_for_help($kopfstein_count_button->{"speed"}[$i], 1711 #[M"Langsamfahrstrecken in Zeitberechnung aufnehmen", "", ""]); 1712 } 1713} 1714 1715change_active_speed_power($active_speed_power{Type}, $active_speed_power{Index}); 1716 1717##### Wind & Wetter ##### 1718$wind_frame = $top_frame->Frame 1719 (-relief => 'raised', -bd => 1); 1720my $wb = $wind_frame->Button 1721 (-textvariable => \$act_value{Windlabel}, 1722 -class => 'FlatBut', 1723 -command => sub { update_weather(1) }, 1724 -width => 22)->pack; 1725$ch->attach($wb, -pod => "^\\s*Datum der Winddaten"); 1726 1727my $wff = $wind_frame->Frame->pack(-fill => 'x'); 1728my $wfewb = $wff->Button 1729 (-font => $font{'bold'}, 1730 -textvariable => \$act_value{Wind}, 1731 -class => 'FlatBut', 1732 -command => \&enter_wind, 1733 )->pack(-fill => 'x', -expand => 1, -side => 'left'); 1734$ch->attach($wfewb, -pod => "^\\s*Winddaten"); 1735 1736my $wfemb = $wff->Menubutton; 1737# Hack: Verwendung von -disabledforeground, weil es kein "label"-Kommando gibt. 1738my $wbm = $wfemb->Menu(-title => M("Wetterdaten"), 1739 -disabledforeground => $wb->cget(-foreground)); 1740$wbm->command(-label => M("Wetterstation").":", 1741 -state => 'disabled', 1742 -font => $font{'bold'}, 1743 ); 1744 1745{ 1746 my @weather_src; 1747 if (!$city_obj->is_osm_source) { 1748 @weather_src = (['uptodate' => M"aktuellste"], 1749 ['dahlem2'], 1750 ['dahlem1'], 1751 ($devel_host && $advanced 1752 ? (['wetterkarte' => 'Wetterkarte Berlin-Dahlem'], 1753 ['metar-EDDT' => 'METAR Tegel'], 1754 ['metar-EDDB' => 'METAR Sch�nefeld'], 1755 ) 1756 : () 1757 ), 1758 ); 1759 } else { 1760 my $icao_file; 1761 if (-r "$datadir/icao_metar") { 1762 $icao_file = "$datadir/icao_metar"; 1763 } elsif (-r "$datadir/icao") { 1764 $icao_file = "$datadir/icao"; 1765 } 1766 if ($icao_file) { 1767 eval { 1768 my $icao_s = Strassen->new_stream($icao_file); 1769 $icao_s->read_stream(sub { 1770 my($r, undef, $line) = @_; 1771 if (my($icao, $fullname) = $r->[Strassen::NAME] =~ m{^(\S+)\s+\((.*)\)}) { 1772 push @weather_src, ["metar-$icao" => "METAR $fullname"]; 1773 } else { 1774 warn "Cannot parse '$r->[Strassen::NAME]' at line $line in $datadir/icao\n"; 1775 } 1776 }); 1777 }; 1778 warn $@ if $@; 1779 } 1780 } 1781 1782 foreach (@weather_src) { 1783 my $name = $_->[1]; 1784 if (!defined $name) { 1785 $name = $wetter_name{$_->[0]} 1786 } 1787 $wbm->radiobutton 1788 (-label => $name, 1789 -variable => \$wetter_station, 1790 -value => $_->[0], 1791 -command => sub { update_weather($wetter_force_update) }, 1792 ); 1793 } 1794 if (@weather_src) { 1795 $wbm->separator; 1796 } 1797} 1798 1799$wbm->command(-label => M('Quelle').':', 1800 -state => 'disabled', 1801 -font => $font{'bold'}, 1802 ); 1803foreach ([M"WWW", 'www'], 1804 [M"lokaler Cache", 'local'], 1805 [M"Datenbank", 'db'], 1806 ) { 1807 next if $_->[1] eq 'db' && !wetter_dir_exists(); 1808 next if $_->[1] eq 'local' && !$devel_host; 1809 $wbm->checkbutton 1810 (-label => $_->[0], 1811 -variable => \$wetter_source{$_->[1]}, 1812 -command => sub { update_weather($wetter_force_update) }, 1813 ); 1814} 1815if (wetter_dir_exists()) { 1816 $wbm->separator; 1817 $wbm->command(-label => M('Auswahl aus Datenbank').':', 1818 -state => 'disabled', 1819 -font => $font{'bold'}, 1820 ); 1821 $wbm->command(-label => M"Dahlem (kurz)", 1822 -command => sub { show_weather_db('dahlem2') }); 1823 $wbm->command(-label => M"Dahlem (lang)", 1824 -command => sub { show_weather_db('dahlem1') }); 1825# $wbm->command(-label => M"Tempelhof", 1826# -command => sub { show_weather_db('tempelhof') }); 1827} 1828$wbm->separator; 1829$wbm->command(-label => M"Wind ignorieren", 1830 -command => sub { ignore_weather() }, 1831 ); 1832{ 1833 my $index = $wbm->index('last'); 1834 push @edit_mode_cmd, sub { $wbm->invoke($index) }; 1835} 1836 1837$wbm->command(-label => M"Aktualisierung", 1838 -command => sub { update_weather(1) }, 1839 ); 1840$wbm->checkbutton(-label => M"automatische Aktualisierung", 1841 -variable => \$wetter_force_update, 1842 -command => sub { update_weather($wetter_force_update) }, 1843 ); 1844$wbm->checkbutton(-label => M"automatische Routenaktualisierung", 1845 -variable => \$wetter_route_update, 1846 ); 1847 1848menuright($wb, $wbm); 1849menuright($wfewb, $wbm); 1850menuarrow($wfemb, $wbm, undef, '-pack' => [-side => 'bottom']); 1851 1852if ($wind_frame->can('UnderlineAll')) { $wind_frame->UnderlineAll } 1853 1854$temp_frame = $top_frame->Frame 1855 (-relief => 'raised', -bd => 1); 1856$ch->attach($temp_frame, -pod => "^\\s*Temp\$"); 1857$temp_frame->Button 1858 (-text => 'Temp', 1859 -width => 7, 1860 -class => 'FlatBut', 1861 -command => sub { 1862 require WWWBrowser; 1863 require BBBikeWeather; 1864 BBBikeWeather::require_wettermeldung(); 1865 WWWBrowser::start_browser("http://$wettermeldung2::www_site{dahlem1}$wettermeldung2::loc{dahlem1}"); 1866 } 1867 )->pack; 1868$temp_frame->Label(-textvariable => \$act_value{Temp}, 1869 )->pack; 1870 1871arrange_topframe(); 1872 1873##### Iconframe ####################################################### 1874 1875$check_sub{'s'} = sub { 1876 plot("str",'s'); 1877}; 1878$check_sub{'l'} = sub { 1879 plot("str",'l'); 1880}; 1881$check_sub{'u'} = sub { 1882 $p_draw{'u'} = $p_draw{'sperre_u'} = $str_draw{'u'}; 1883 $progress->InitGroup; 1884 plot("str",'u'); 1885 plot("p",'u'); 1886 plot_sperre($p_file{"sperre_u"}, -abk => "sperre_u"); 1887 $progress->FinishGroup; 1888}; 1889$check_sub{'b'} = sub { 1890 $p_draw{'b'} = $p_draw{'sperre_b'} = $str_draw{'b'}; 1891 $progress->InitGroup; 1892 plot('str','b'); 1893 plot('p','b'); 1894 plot_sperre($p_file{"sperre_b"}, -abk => "sperre_b"); 1895 $progress->FinishGroup; 1896}; 1897$check_sub{'r'} = sub { 1898 $p_draw{'r'} = $str_draw{'r'}; 1899 $progress->InitGroup; 1900 plot('str','r'); 1901 plot('p','r'); 1902 $progress->FinishGroup; 1903}; 1904$check_sub{'w'} = sub { 1905 plot('str','w'); 1906}; 1907$check_sub{'f'} = sub { 1908 plot('str','f'); 1909}; 1910$check_sub{'o'} = sub { plot('p','o',Shortname => 1) }; 1911$check_sub{'p'} = sub { plot('p','p') }; 1912 1913## DEBUG_BEGIN 1914#BEGIN{mymstat("before do_iconframe BEGIN");} mymstat("before do_iconframe"); 1915## DEBUG_END 1916$DockFrame = 'Frame'; 1917 1918# use FlatCheckbox or not? 1919# flat relief relies on Tie::Watch installed 1920if ($flat_relief and !eval 'require Tie::Watch; 1') { 1921 $flat_relief = 0; 1922} 1923$Checkbutton = 'Checkbutton'; 1924$Radiobutton = 'Radiobutton'; 1925if ($flat_relief) { 1926 eval { require Tk::FlatCheckbox }; 1927 if (!$@) { 1928 $Checkbutton = 'FlatCheckbox'; 1929 if ($os ne 'win') { 1930 $top->optionAdd('*FlatCheckbox*background' => 'grey80', 1931 "startupFile"); 1932 } 1933 } 1934 eval { require Tk::FlatRadiobutton }; 1935 if (!$@) { 1936 $Radiobutton = 'FlatRadiobutton'; 1937 if ($os ne 'win') { 1938 $top->optionAdd('*FlatRadiobutton*background' => 'grey80', 1939 "startupFile"); 1940 } 1941 } 1942} 1943 1944$splash_screen->Update(0.2, 'create iconframe') if $splash_screen; 1945 1946do_iconframe() if $do_iconframe; 1947if ($standard_menubar) { 1948## DEBUG_BEGIN 1949#mymstat("before set menubar"); 1950## DEBUG_END 1951 BBBike::Menubar::Set(); 1952} 1953## DEBUG_BEGIN 1954#BEGIN{mymstat("after do_iconframe BEGIN");} 1955## DEBUG_END 1956 1957# Erzeugt das Frame mit den Icons und den dazugeh�rigen Men�s 1958sub do_iconframe { 1959 my $sym_frame = $ctrl_frame->Frame 1960 (Name => 'symframe')->pack(-side => 'top', -anchor => 'w'); 1961 1962 my $def_selectcolor; 1963 { 1964 # get default selectcolor 1965 my $cb = $top->Checkbutton; 1966 $def_selectcolor = $cb->cget(-selectcolor); 1967 $cb->destroy; 1968 } 1969 1970 $top->optionAdd('*symframe*padX' => 0, 'startupFile'); 1971 $top->optionAdd('*symframe*padY' => 0, 'startupFile'); 1972 # XXX ja? 1973 $top->optionAdd('*symframe*indicatorOn' => $flat_relief, 'startupFile'); 1974 $top->optionAdd('*symframe*selectColor' => 'white', 'startupFile') 1975 unless $flat_relief; 1976 $top->optionAdd('*symframe*Menu*selectColor' => $def_selectcolor, 1977 'startupFile'); 1978 if ($flat_relief) { 1979 $top->optionAdd('*symframe*relief' => 'flat'); 1980 $top->optionAdd('*symframe*Menu*relief' => 'raised'); 1981 } 1982 1983 if ($small_icons) { 1984 foreach (qw(Button Checkbutton Radiobutton Menubutton 1985 FlatCheckbox FlatRadiobutton FireButton)) { 1986 $top->optionAdd('*symframe*$_*padY' => 0, 'startupFile'); 1987 } 1988 } 1989 1990 my($dock_port, $dock_port2); 1991 eval { 1992 die; # XXX not ready.... 1993 require Tk::DockFrame; 1994 $DockFrame = 'DockFrame'; 1995 $dock_port = $sym_frame->DockPort->grid(-row => 0, 1996 -column => 0, 1997 -sticky => 'nw'); 1998 $dock_port2 = $sym_frame->DockPort->grid(-row => 0, 1999 -column => 1, 2000 -sticky => 'nw'); 2001 }; 2002 2003 use vars qw($curr_row); 2004 local $curr_row = 0; 2005 $misc_frame = $sym_frame->$DockFrame 2006 (-bd => 1, -relief => 'raised', 2007 ($DockFrame eq 'DockFrame' ? ('-dock' => $dock_port) : ())); 2008 if ($DockFrame ne 'DockFrame') { 2009 $misc_frame->grid(-row => 0, 2010 -column => 0, 2011 -sticky => 'nsew'); 2012 } 2013 $misc_frame->gridColumnconfigure(999, -weight => 1); # force buttons to the left 2014 $col = 0; 2015##### Stra�en ##### 2016my $strasse_check; 2017my $strcm; 2018my $radwege_check_index; 2019my $qualitaet_check_index; 2020my $handicap_check_index; 2021my $sperre_check_index; 2022my $ampeln_check_index; 2023my $fragezeichen_check_index; 2024my $nolighting_check_index; 2025my $gruene_wege_check_index; 2026my $vorfahrt_check_index; 2027my $c_bpcm; 2028my $comments_all_check_index; 2029my $cycle_routes_check_index; 2030unless($skip_features{"strassen"}) { 2031 $strasse_photo = load_photo($misc_frame, 'strasse'); 2032 $strasse_check = $misc_frame->$Checkbutton 2033 (image_or_text($strasse_photo, 'Str'), 2034 -variable => \$str_draw{'s'}, 2035 -command => $check_sub{'s'}, 2036 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 2037 $balloon->attach($strasse_check, -msg => M"Stra�en"); 2038 $ch->attach($strasse_check, -pod => "^\\s*Stra�en-Symbol"); 2039 2040 my $strcmb = $misc_frame->Menubutton; 2041 $strcmb->focus; 2042 $strcm = $strcmb->Menu(-title => M("Stra�en")); 2043 menu_entry_choose_ort 2044 ($strcm, 's', 2045 -accelerator => 'S', 2046 -strchooseortargs => 2047 {'-markstartifactive' => 1, 2048 (!$city_obj->is_osm_source 2049 ? (-completelistbutton => sub { choose_from_plz(-interactive => 1) }, 2050 -completelistbuttonlabel => M"Alle Stra�en" 2051 ) 2052 : () 2053 ), 2054 }, 2055 -strextrachoosemenuaction => 2056 sub { 2057 $strcm->cascade(-label => M('Erweiterte Auswahl').' ...'); 2058 my $ausm = $strcm->Menu(-title => M("Erweiterte Auswahl").' ...'); 2059 $strcm->entryconfigure('last', -menu => $ausm); 2060 $ausm->command(-label => M"Volltextsuche", 2061 -accelerator => "Ctrl-F", 2062 -command => sub { 2063 require BBBikeAdvanced; 2064 search_anything(); 2065 }); 2066 $plzmcmd = $ausm->command 2067 (-label => M"Komplette Stra�enliste", 2068 -command => sub { choose_from_plz(-interactive => 1) }); 2069 if ($advanced) { 2070 $ausm->command 2071 (-label => M"Telefonbuch-Datenbank (Stra�e)", 2072 -command => sub { 2073 telefonbuch_dialog("str"); 2074 }); 2075 $ausm->command 2076 (-label => M"Telefonbuch-Datenbank (Name)", 2077 -command => sub { 2078 telefonbuch_dialog("tel"); 2079 }); 2080 $ausm->command(-label => M"MySQL-DB", 2081 -command => sub { 2082 push @INC, "$FindBin::RealBin/miscsrc"; 2083 eval { 2084 require TelbuchDBApprox; 2085 TelbuchDBApprox::tk_choose($top); 2086 }; 2087 if ($@) { 2088 status_message($@, "die"); 2089 } 2090 }); 2091 } 2092 }, 2093 ); 2094 $strcm->separator; 2095 if ($os ne 'win' || $advanced) { 2096 # No rotation on win possible. 2097 $strcm->checkbutton(-label => M"Stra�ennamen", 2098 -variable => \$str_name_draw{'s'}, 2099 -command => sub { 2100 pending(1, 'replot-str-s'); 2101 }, 2102 ); 2103 } 2104 $strcm->cascade(-label => M"Stra�enkategorien"); 2105 { 2106 my $skm = $strcm->Menu(-title => M"Stra�enkategorien"); 2107 $strcm->entryconfigure('last', -menu => $skm); 2108 my @l = ([M"wichtige Hauptstra�en", 'HH'], 2109 [M"Hauptstra�en", 'H'], 2110 ($devel_host || $city_obj->is_osm_source ? [M"wichtige Nebenstra�e", 'NH'] : ()), # XXX good name for this? Some osm records have the comment "Erg�nzungsstra�e mit besonderer Bedeutung" 2111 [M"Nebenstra�en", 'N'], 2112 [M"f�r Kfz gesperrte Stra�en", 'NN']); 2113 foreach (@l) { 2114 my($label,$cat) = @$_; 2115 $skm->checkbutton 2116 (-label => $label, 2117 -variable => \$str_restrict{'s'}->{$cat}, 2118 -command => sub { 2119 pending(1, 'replot-str-s'); 2120 }, 2121 ); 2122 } 2123 if ($advanced) { 2124 $skm->separator; 2125 $skm->checkbutton 2126 (-label => M"Autobahnen/Kfz-Stra�en", 2127 -variable => \$str_draw{'sBAB'}, 2128 -command => sub { 2129 plot("str", "sBAB", 2130 -filename => get_strassen_file("strassen_bab")); 2131 }, 2132 ); 2133 } 2134 2135 } 2136 $strcm->checkbutton(-label => M"Radwege", 2137 -variable => \$str_draw{'rw'}, 2138 -command => sub { plot('str','rw')}, 2139 -accelerator => 'Shift-R', 2140 ); 2141 $radwege_check_index = $strcm->index('last'); 2142 $strcm->cascade(-label => M"Radwegekategorien"); 2143 { 2144 my $rkm = $strcm->Menu(-title => M"Radwegekategorien"); 2145 $strcm->entryconfigure('last', -menu => $rkm); 2146 foreach my $t (@Radwege::category_order) { 2147 my $cat_code = $Radwege::category_code{$t} || ''; 2148 next if $cat_code eq 'RW0'; 2149 $rkm->checkbutton 2150 (-label => $Radwege::category_name{$t}, 2151 -variable => \$str_restrict{'rw'}->{$cat_code}, 2152 -command => sub { 2153 pending(1, 'replot-str-rw'); 2154 }, 2155 ); 2156 } 2157 } 2158 2159 my $create_comment_layers_cb = sub { 2160 my($menu, $type, %cb_args) = @_; 2161 my $label = $comment_cat_labels{$type} || $type; 2162 my $def = 'comm-' . $type; 2163 $menu->checkbutton 2164 (-label => $label, 2165 -variable => \$str_draw{$def}, 2166 -command => sub { 2167 my $file = get_strassen_file("comments_" . $type); 2168 plot('str', $def, Filename => $file); 2169 }, 2170 %cb_args, 2171 ); 2172 }; 2173 2174 unless ($skip_features{"radroute"}) { 2175 $create_comment_layers_cb->($strcm, "route", -accelerator => 'Shift-Y'); 2176 $cycle_routes_check_index = $strcm->index('last'); 2177 $strcm->command(-label => M"Radroute ausw�hlen", 2178 -command => sub { 2179 choose_ort(qw(s comm-route), 2180 -markstartifactive => 1); 2181 }); 2182 } 2183 2184 $strcm->checkbutton(-label => M"Einbahn-/gesperrte Stra�en", 2185 -variable => \$p_draw{'sperre'}, 2186 -command => sub { plot_sperre() }, 2187 -accelerator => 'G', 2188 ); 2189 $sperre_check_index = $strcm->index('last'); 2190 $strcm->checkbutton(-label => M"Ampeln", 2191 -variable => \$p_draw{'lsa'}, 2192 -command => sub { plot('p','lsa') }, 2193 -accelerator => 'A', 2194 ); 2195 $ampeln_check_index = $strcm->index('last'); 2196 $strcm->checkbutton(-label => M"Stra�enqualit�t", 2197 -variable => \$str_draw{'qs'}, 2198 -command => sub { plot('str','qs') }, 2199 -accelerator => 'Shift-Q', 2200 ); 2201 $qualitaet_check_index = $strcm->index('last'); 2202 $strcm->cascade(-label => M"Qualit�tskategorien"); 2203 { 2204 my $qm = $strcm->Menu(-title => M"Qualit�tskategorien"); 2205 $strcm->entryconfigure('last', -menu => $qm); 2206 foreach (0 .. 3) { 2207 my $cat = "Q$_"; 2208 my $label = $category_attrib{$cat}->[ATTRIB_SINGULAR]; 2209 $qm->checkbutton 2210 (-label => $label, 2211 -variable => \$str_restrict{'qs'}->{$cat}, 2212 -command => sub { 2213 $str_restrict{'ql'}->{$cat} = 2214 $str_restrict{'qs'}->{$cat}; 2215 pending(1, 'replot-str-qs'); 2216 pending(1, 'replot-str-ql'); 2217 }, 2218 ); 2219 } 2220 } 2221 $strcm->checkbutton(-label => M"Sonstige Beeintr�chtigungen", 2222 -variable => \$str_draw{'hs'}, 2223 -command => sub { plot('str','hs') }, 2224 -accelerator => 'Shift-H', 2225 ); 2226 $handicap_check_index = $strcm->index('last'); 2227 unless ($skip_features{"nolighting"}) { 2228 $strcm->checkbutton(-label => M"Unbeleuchtete Stra�en", 2229 -variable => \$str_draw{'nl'}, 2230 -command => sub { plot('str','nl') }, 2231 -accelerator => 'Shift-N', 2232 ); 2233 $nolighting_check_index = $strcm->index('last'); 2234 } 2235 unless ($skip_features{"green"}) { 2236 $strcm->checkbutton(-label => M"Gr�ne Wege", 2237 -variable => \$str_draw{'gr'}, 2238 -command => sub { plot('str','gr') }, 2239 -accelerator => 'Shift-G', 2240 ); 2241 $gruene_wege_check_index = $strcm->index('last'); 2242 } 2243 unless ($skip_features{"vorfahrt"}) { 2244 $strcm->checkbutton(-label => M"Vorfahrt", 2245 -variable => \$p_draw{'vf'}, 2246 -command => sub { plot('p','vf') }, 2247 -accelerator => 'Shift-V', 2248 ); 2249 $vorfahrt_check_index = $strcm->index('last'); 2250 } 2251 2252 $strcm->cascade(-label => M"Kommentare"); 2253 { 2254 $c_bpcm = $strcm->Menu(-title => M"Sonstige"); 2255 $strcm->entryconfigure("last", -menu => $c_bpcm); 2256 my @used_types; 2257 foreach my $type (@comments_types) { 2258 next if $type =~ /^(cyclepath|mount|route|ferry)$/; # handled elsewhere 2259 if (!$advanced) { 2260 # kfzverkehr: poor presentation 2261 # scenic: almost no data 2262 next if $type =~ /^(kfzverkehr|scenic)$/; 2263 } 2264 $create_comment_layers_cb->($c_bpcm, $type); 2265 push @used_types, $type; 2266 } 2267 $c_bpcm->separator; 2268 my $str_draw_all = 0; 2269 $c_bpcm->checkbutton 2270 (-label => M("Alle"), 2271 -variable => \$str_draw_all, 2272 -command => sub { 2273 my $onoff = $str_draw_all; 2274 $progress->InitGroup; 2275 for my $type (@used_types) { 2276 my $def = 'comm-' . $type; 2277 $str_draw{$def} = $onoff; 2278 plot('str', $def, Filename => get_strassen_file("comments_" . $type)); 2279 } 2280 $progress->FinishGroup; 2281 }, 2282 -accelerator => 'Shift-C', 2283 ); 2284 $comments_all_check_index = $c_bpcm->index('last'); 2285 } 2286 2287 unless ($skip_features{"hoehe"}) { 2288 $strcm->checkbutton(-label => M"H�henangaben", 2289 -variable => \$p_draw{'hoehe'}, 2290 -command => sub { plot('p','hoehe') }); 2291 } 2292 2293 # XXX the mount file is very problematic at the moment; do not show it to the normal user until everything's fixed! See StrassenNetz.pm and steigung_stat. Also, I think comments_mount is not used for Steigungsoptimierung, so don't puzzle the user about this. 2294 if ($devel_host) { 2295 $strcm->checkbutton 2296 (-label => M"Steigungen", 2297 -variable => \$str_draw{'mount'}, 2298 -command => \&plot_mount, 2299 ); 2300 } 2301 if (1) { 2302 $strcm->checkbutton(-label => M"Fragezeichen", 2303 -variable => \$str_draw{'fz'}, 2304 -command => sub { plot('str','fz') }, 2305 -accelerator => '?', 2306 ); 2307 $fragezeichen_check_index = $strcm->index('last'); 2308 } 2309 $strcm->checkbutton(-label => M"Outline zeichnen", 2310 -variable => \$str_outline{'s'}, 2311 -command => sub { 2312 pending(1, 'replot-str-s'); 2313 }, 2314 ); 2315 menu_entry_up_down($strcm, $tag_group{'str_s'}); 2316 menuright($strasse_check, $strcm); 2317 menuarrow($strcmb, $strcm, $col++, -special => 'LAYER'); 2318} 2319##### Landstra�en ##### 2320my $landstrasse_check; 2321my $lstrcm; 2322my $radwege_l_check_index; 2323my $qualitaet_l_check_index; 2324my $handicap_l_check_index; 2325my $land_jwd_check_index; 2326unless ($skip_features{"landstrassen"}) { 2327 $landstrasse_photo = 2328 load_photo($misc_frame, 'landstrasse'); 2329 $landstrasse_check = $misc_frame->$Checkbutton 2330 (image_or_text($landstrasse_photo, 'LStr'), 2331 -variable => \$str_draw{'l'}, 2332 -command => $check_sub{'l'}, 2333 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 2334 $balloon->attach($landstrasse_check, -msg => M"Landstra�en"); 2335 $ch->attach($landstrasse_check, -pod => "^\\s*Landstra�en-Symbol"); 2336 2337 my $lstrcmb = $misc_frame->Menubutton; 2338 $lstrcm = $lstrcmb->Menu(-title => M"Landstra�en"); 2339 menu_entry_choose_ort($lstrcm, 'l', 2340 -accelerator => 'L', 2341 -strchooseortargs => {'-markstartifactive' => 1}); 2342 $lstrcm->separator; 2343 $lstrcm->checkbutton(-label => M"Outline zeichnen", 2344 -variable => \$str_outline{'l'}, 2345 -command => sub { 2346 pending(1, 'replot-str-l'); 2347 }, 2348 ); 2349 unless ($skip_features{wideregion}) { 2350 $lstrcm->checkbutton(-label => M"Landstra�en jwd zeichnen", 2351 -variable => \$str_far_away{'l'}, 2352 -command => sub { 2353 pending(1, 'replot-str-l'); 2354 }, 2355 -accelerator => 'Shift-L', 2356 ); 2357 $land_jwd_check_index = $lstrcm->index('last'); 2358 } 2359 $lstrcm->checkbutton(-label => M"Stra�ennamen", 2360 -variable => \$str_name_draw{'l'}, 2361 -command => sub { 2362 pending(1, 'replot-str-l'); 2363 }, 2364 ); 2365 $lstrcm->checkbutton(-label => M"Stra�ennummern", 2366 -variable => \$str_nr_draw{'l'}, 2367 -command => sub { 2368 pending(1, 'replot-str-l'); 2369 }, 2370 ); 2371 $lstrcm->checkbutton(-label => M"Stra�enqualit�t", 2372 -variable => \$str_draw{'ql'}, 2373 -command => sub { plot('str','ql') }, 2374 -accelerator => 'Shift-Q', 2375 ); 2376 $qualitaet_l_check_index = $lstrcm->index('last'); 2377 $lstrcm->checkbutton(-label => M"Sonstige Beeintr�chtigungen", 2378 -variable => \$str_draw{'hl'}, 2379 -command => sub { plot('str','hl') }, 2380 ); 2381 $handicap_l_check_index = $lstrcm->index('last'); 2382 $lstrcm->checkbutton(-label => M"Radwege im Umland", 2383 -variable => \$str_draw{'comm-cyclepath'}, 2384 -command => sub { 2385 my $file = get_strassen_file("comments_cyclepath"); 2386 plot('str', 'comm-cyclepath', Filename => $file); 2387 }, 2388 -accelerator => 'Shift-R', 2389 ); 2390 $radwege_l_check_index = $lstrcm->index('last'); 2391 menu_entry_up_down($lstrcm, $tag_group{'str_l'}); 2392 menuright($landstrasse_check, $lstrcm); 2393 menuarrow($lstrcmb, $lstrcm, $col++, -special => 'LAYER'); 2394} 2395 2396##### Orte ##### 2397my $ort_check; 2398my $ocm; 2399my $ort_jwd_check_index; 2400unless ($skip_features{"orte"}) { 2401 $ort_photo = load_photo($misc_frame, 'ort'); 2402 $ort_check = $misc_frame->$Checkbutton 2403 (image_or_text($ort_photo, 'Ort'), 2404 -variable => \$p_draw{'o'}, 2405 -command => $check_sub{'o'}, 2406 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 2407 $balloon->attach($ort_check, -msg => M"Orte im Umland"); 2408 $ch->attach($ort_check, -pod => "^\\s*Ort-Symbol"); 2409 2410 my $ocmb = $misc_frame->Menubutton; 2411 $ocm = $ocmb->Menu(-title => M"Orte"); 2412 menu_entry_choose_ort($ocm, 'o', -accelerator_p => 'O', 2413 -pchooseortargs => {'-markstartifactive' => 1}); 2414 $ocm->separator; 2415 $ocm->checkbutton(-label => M"Ortsnamen", 2416 -variable => \$p_name_draw{'o'}, 2417 -command => sub { 2418 pending(1, 'replot-p-o'); 2419 }, 2420 ); 2421 $ocm->cascade(-label => M"Kategorie"); 2422 { 2423 my $m = $ocm->Menu(-title => M"Ortkategorie"); 2424 $ocm->entryconfigure('last', -menu => $m); 2425 for my $cat ('auto', 0 .. 5) { 2426 $m->radiobutton(-label => ($cat eq 'auto' ? M"Auto" : 2427 $cat == 0 ? M"Alle" : $cat), 2428 -variable => \$place_category, 2429 -value => $cat, 2430 -command => sub { 2431 pending(1, 'replot-p-o'); 2432 }, 2433 ); 2434 } 2435 } 2436 unless ($skip_features{wideregion}) { 2437 $ocm->checkbutton(-label => M"Orte jwd zeichnen", 2438 -variable => \$p_far_away{'o'}, 2439 -command => sub { 2440 pending(1, 'replot-p-o'); 2441 }, 2442 -accelerator => 'Shift-O', 2443 ); 2444 $ort_jwd_check_index = $ocm->index('last'); 2445 } 2446 $ocm->separator; 2447 $ocm->cascade(-label => M"Schriftgr��e"); 2448 { 2449 my $m = $ocm->Menu(-title => M"Ort-Schriftgr��e"); 2450 $ocm->entryconfigure('last', -menu => $m); 2451 foreach my $fontsize ([M"klein", 0], 2452 [M"normal", 1], 2453 [M"gro�", 2], 2454 [M"sehr gro�", 3], 2455 ) { 2456 $m->radiobutton(-label => $fontsize->[0], 2457 -variable => \$orte_label_size, 2458 -value => $fontsize->[1], 2459 -command => sub { 2460 pending(1, 'replot-p-o'); 2461 }, 2462 ); 2463 } 2464 } 2465 $ocm->checkbutton(-label => M"�berlappungen vermeiden", 2466 -variable => \$no_overlap_label{'o'}, 2467 -command => sub { 2468 pending(1, 'replot-p-o'); 2469 }, 2470 ); 2471 if ($advanced) { # XXX funktioniert noch nicht mit no_verlap zusammen 2472 $ocm->checkbutton(-label => M"Umrandung um Labels", 2473 -variable => \$do_outline_text{'o'}, 2474 -command => sub { 2475 pending(1, 'replot-p-o'); 2476 }, 2477 ); 2478 } 2479 menu_entry_up_down($ocm, $tag_group{'p_o'}); 2480 menuright($ort_check, $ocm); 2481 menuarrow($ocmb, $ocm, $col++, -special => 'LAYER'); 2482} 2483 2484##### U-Bahn ##### 2485my $ubahn_check; 2486unless ($skip_features{"u-bahn"}) { 2487 $ubahn_photo = load_photo($misc_frame, 'ubahn'); 2488 $ubahn_check = $misc_frame->$Checkbutton 2489 (image_or_text($ubahn_photo, 'U'), 2490 -variable => \$str_draw{'u'}, 2491 -command => $check_sub{'u'}, 2492 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 2493 $balloon->attach($ubahn_check, -msg => M"U-Bahn"); 2494 $ch->attach($ubahn_check, -pod => "^\\s*U-Bahn-Symbol"); 2495 2496 my $ubcmb = $misc_frame->Menubutton; 2497 my $ubcm = $ubcmb->Menu(-title => M"U-Bahn"); 2498 menu_entry_choose_ort($ubcm, 'u', -accelerator => 'U', 2499 -pchooseortargs => {'-markstartifactive' => 1}, 2500 -strblockings => 1, 2501 ); 2502 $ubcm->checkbutton(-label => M"U-Bhf-Namen", 2503 -variable => \$p_name_draw{'u'}, 2504 -command => sub { 2505 pending(1, 'replot-p-u'); 2506 }, 2507 ); 2508 $ubcm->checkbutton(-label => M"�berlappungen vermeiden", 2509 -variable => \$no_overlap_label{'u'}, 2510 -command => sub { 2511 pending(1, 'replot-p-u'); 2512 }, 2513 ); 2514 $ubcm->checkbutton(-label => M"Fahrradfreundliche Zug�nge", 2515 -variable => \$p_draw{'u_bg'}, 2516 -command => sub { 2517 plot('p', 'u_bg'); 2518 }, 2519 ); 2520 $ubcm->separator; 2521 foreach ($skip_features{"vbb"} ? ["Strecken in Betrieb", "UA"] : 2522 ([M"VBB-Zone Berlin A", 'UA'], 2523 [M"VBB-Zone Berlin B", 'UB'], 2524 ), 2525 [M"nur Betriebsfahrten", "UBetrieb"], 2526 [M"in Bau", 'UBau'], 2527 [M"stillgelegt", 'U0'], 2528 ) { 2529 my($label,$cat) = @$_; 2530 $ubcm->checkbutton(-label => $label, 2531 -variable => \$str_restrict{'u'}->{$cat}, 2532 -command => sub { 2533 $progress->InitGroup; 2534 pending(1, 'replot-str-u'); 2535 pending(1, 'replot-p-u'); 2536 $progress->FinishGroup; 2537 }, 2538 ); 2539 } 2540 menu_entry_up_down($ubcm, $tag_group{'str_u'}); 2541 menuright($ubahn_check, $ubcm); 2542 menuarrow($ubcmb, $ubcm, $col++, 2543 -menulabel => M"U-Bahn", -special => 'LAYER'); 2544} 2545##### S-Bahn ##### 2546my $sbahn_check; 2547unless ($skip_features{"s-bahn"}) { 2548 $sbahn_photo = load_photo($misc_frame, 'sbahn'); 2549 $sbahn_check = $misc_frame->$Checkbutton 2550 (image_or_text($sbahn_photo, 'S'), 2551 -variable => \$str_draw{'b'}, 2552 -command => $check_sub{'b'}, 2553 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 2554 $balloon->attach($sbahn_check, -msg => M"S-Bahn"); 2555 $ch->attach($sbahn_check, -pod => "^\\s*S-Bahn-Symbol"); 2556 my $sbcmb = $misc_frame->Menubutton; 2557 my $sbcm = $sbcmb->Menu(-title => M"S-Bahn"); 2558 menu_entry_choose_ort($sbcm, 'b', -accelerator => 'B', 2559 -pchooseortargs => {'-markstartifactive' => 1}, 2560 -strblockings => 1, 2561 ); 2562 $sbcm->checkbutton(-label => M"S-Bhf-Namen", 2563 -variable => \$p_name_draw{'b'}, 2564 -command => sub { 2565 pending(1, 'replot-p-b'); 2566 }, 2567 ); 2568 $sbcm->checkbutton(-label => M"�berlappungen vermeiden", 2569 -variable => \$no_overlap_label{'b'}, 2570 -command => sub { 2571 pending(1, 'replot-p-b'); 2572 }, 2573 ); 2574 $sbcm->checkbutton(-label => M"Fahrradfreundliche Zug�nge", 2575 -variable => \$p_draw{'b_bg'}, 2576 -command => sub { 2577 plot('p', 'b_bg'); 2578 }, 2579 ); 2580 $sbcm->separator; 2581 foreach ($skip_features{"vbb"} ? ["Strecken in Betrieb", "SA"] : 2582 ([M"VBB-Zone Berlin A", 'SA'], 2583 [M"VBB-Zone Berlin B", 'SB'], 2584 [M"VBB-Zone Berlin C", 'SC'], 2585 ), 2586 [M"nur Betriebsfahrten", "SBetrieb"], 2587 [M"in Bau", 'SBau'], 2588 [M"stillgelegt", 'S0'], 2589 ) { 2590 my($label,$cat) = @$_; 2591 $sbcm->checkbutton(-label => $label, 2592 -variable => \$str_restrict{'b'}->{$cat}, 2593 -command => sub { 2594 $progress->InitGroup; 2595 pending(1, 'replot-str-b'); 2596 pending(1, 'replot-p-b'); 2597 $progress->FinishGroup; 2598 }, 2599 ); 2600 } 2601 menu_entry_up_down($sbcm, $tag_group{'str_b'}); 2602 menuright($sbahn_check, $sbcm); 2603 menuarrow($sbcmb, $sbcm, $col++, 2604 -menulabel => M"S-Bahn", -special => 'LAYER'); 2605} 2606##### RB ##### 2607my $rbahn_check; 2608unless ($skip_features{"r-bahn"}) { 2609 if ($XXX_use_old_R_symbol) { 2610 $rbahn_photo = load_photo($misc_frame, 'rbahn'); 2611 } else { 2612 $rbahn_photo = load_photo($misc_frame, 'eisenbahn15'); 2613 } 2614 $rbahn_check = $misc_frame->$Checkbutton 2615 (image_or_text($rbahn_photo, 'RB'), 2616 -variable => \$str_draw{'r'}, 2617 -command => $check_sub{'r'}, 2618 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 2619 $balloon->attach($rbahn_check, -msg => M"Regionalbahn"); 2620 $ch->attach($rbahn_check, -pod => "^\\s*RB-Symbol"); 2621 my $rbcmb = $misc_frame->Menubutton; 2622 my $rbcm = $rbcmb->Menu(-title => M"Regionalbahn"); 2623 menu_entry_choose_ort($rbcm, 'r', -accelerator => 'R', 2624 -pchooseortargs => {'-markstartifactive' => 1}, 2625 -strblockings => 1, 2626 ); 2627 $rbcm->checkbutton(-label => M"R-Bhf-Namen", 2628 -variable => \$p_name_draw{'r'}, 2629 -command => sub { 2630 pending(1, 'replot-p-r'); 2631 }, 2632 ); 2633 $rbcm->checkbutton(-label => M"�berlappungen vermeiden", 2634 -variable => \$no_overlap_label{'r'}, 2635 -command => sub { 2636 pending(1, 'replot-p-r'); 2637 }, 2638 ); 2639 $rbcm->separator; 2640 foreach ($skip_features{"vbb"} ? ["Strecken in Betrieb", "R"] : 2641 ([M"VBB-Zonen Berlin A und B", 'RB'], 2642 [M"VBB-Zone Berlin C", 'RC'], 2643 [M"au�erhalb Berlin ABC", 'R'], 2644 ), 2645 [M"stillgelegt", 'R0'], 2646 [M"in Bau", 'RBau'], 2647 [M"G�terbahnen/Verbindungsstrecken", 'RG'], 2648 [M"Parkbahnen/Kleinbahnen", 'RP'], 2649 ) { 2650 my($label,$cat) = @$_; 2651 $rbcm->checkbutton(-label => $label, 2652 -variable => \$str_restrict{'r'}->{$cat}, 2653 -command => sub { 2654 $progress->InitGroup; 2655 pending(1, 'replot-str-r'); 2656 pending(1, 'replot-p-r'); 2657 $progress->FinishGroup; 2658 }, 2659 ); 2660 } 2661 menu_entry_up_down($rbcm, $tag_group{'str_r'}); 2662 menuright($rbahn_check, $rbcm); 2663 menuarrow($rbcmb, $rbcm, $col++, 2664 -menulabel => M"R-Bahn", -special => 'LAYER'); 2665} 2666##### Ferries ##### 2667unless ($skip_features{'faehren'}) { 2668 $ferry_photo = load_photo($misc_frame, 'ferry'); 2669 my $ferry_check = $misc_frame->$Checkbutton 2670 (image_or_text($ferry_photo, 'F'), 2671 -variable => \$str_draw{'e'}, 2672 -command => sub { plot('str','e') }, 2673 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 2674 $balloon->attach($ferry_check, -msg => M"F�hren"); 2675 my $ferrycmb = $misc_frame->Menubutton; 2676 my $ferrycm = $ferrycmb->Menu(-title => M"F�hren"); 2677 menu_entry_choose_ort($ferrycm, 'e', 2678 -pchooseortargs => {'-markstartifactive' => 1}, 2679 ); 2680 menuright($ferry_check, $ferrycm); 2681 menuarrow($ferrycmb, $ferrycm, $col++, 2682 -menulabel => M"F�hren", -special => 'LAYER'); 2683} 2684##### Gew�sser ##### 2685my $wasser_check; 2686my $wasserumland_check_index; 2687my $wcm; 2688unless ($skip_features{"wasser"}) { 2689 $wasser_photo = load_photo($misc_frame, 'wasser'); 2690 $wasser_check = $misc_frame->$Checkbutton 2691 (image_or_text($wasser_photo, 'H20'), 2692 -variable => \$str_draw{'w'}, 2693 -command => $check_sub{'w'}, 2694 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 2695 $balloon->attach($wasser_check, -msg => M"Gew�sser"); 2696 $ch->attach($wasser_check, -pod => "^\\s*Gew�sser-Symbol"); 2697 my $wcmb = $misc_frame->Menubutton; 2698 $wcm = $wcmb->Menu(-title => M"Gew�sser"); 2699 menu_entry_choose_ort($wcm, 'w', -accelerator => 'W'); 2700 $wcm->separator; 2701 $wcm->checkbutton(-label => M"Outline zeichnen", 2702 -variable => \$str_outline{'w'}, 2703 -command => sub { 2704 $str_outline{'i'} = $str_outline{'w'}; 2705 pending(1, 'replot-str-w'); 2706 }, 2707 ); 2708 $wcm->checkbutton(-label => M"Namen der Gew�sser", 2709 -variable => \$str_name_draw{'w'}, 2710 -command => sub { 2711 $str_name_draw{'i'} = $str_name_draw{'w'}; 2712 pending(1, 'replot-str-w'); 2713 }, 2714 ); 2715 unless ($skip_features{"wasserumland"}) { 2716 $wcm->checkbutton(-label => M"Gew�sser in der Stadt zeichnen", 2717 -variable => \$wasserstadt, 2718 -command => sub { 2719 pending(1, 'replot-str-w'); 2720 }, 2721 ); 2722 $wcm->checkbutton(-label => M"Gew�sser im Umland zeichnen", 2723 -variable => \$wasserumland, 2724 -command => sub { 2725 pending(1, 'replot-str-w'); 2726 }, 2727 -accelerator => 'Shift-W', 2728 ); 2729 $wasserumland_check_index = $wcm->index('last'); 2730 unless ($skip_features{"wideregion"}) { 2731 $wcm->checkbutton(-label => M"Gew�sser jwd zeichnen", 2732 -variable => \$str_far_away{'w'}, 2733 -command => sub { 2734 pending(1, 'replot-str-w'); 2735 }, 2736 ); 2737 } 2738 } 2739 menu_entry_up_down($wcm, $tag_group{'str_w'}); 2740 menuright($wasser_check, $wcm); 2741 menuarrow($wcmb, $wcm, $col++, -special => 'LAYER'); 2742} 2743##### Fl�chen ##### 2744my $flaechen_check; 2745unless ($skip_features{"flaechen"}) { 2746 $flaechen_photo = load_photo($misc_frame, 'flaechen'); 2747 $flaechen_check = $misc_frame->$Checkbutton 2748 (image_or_text($flaechen_photo, 'Fl'), 2749 -variable => \$str_draw{'f'}, 2750 -command => $check_sub{'f'}, 2751 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 2752 $balloon->attach($flaechen_check, -msg => M"sonstige Fl�chen"); 2753 $ch->attach($flaechen_check, -pod => "^\\s*Fl�chen-Symbol"); 2754 my $fcmb = $misc_frame->Menubutton; 2755 my $fcm = $fcmb->Menu(-title => M"sonstige Fl�chen"); 2756 menu_entry_choose_ort($fcm, 'f', -accelerator => 'F'); 2757 $fcm->checkbutton(-label => M"Namen der Fl�chen", 2758 -variable => \$str_name_draw{'f'}, 2759 -command => sub { 2760 pending(1, 'replot-str-f'); 2761 }, 2762 ); 2763 $fcm->separator; 2764 2765 if ($advanced) { 2766 menu_entry_choose_ort($fcm, 'z'); 2767 $fcm->separator; 2768 } 2769 $fcm->checkbutton(-label => $str_attrib{g}->[ATTRIB_PLURAL], 2770 -variable => \$str_draw{'g'}, 2771 -command => sub { plot('str','g') }); 2772 if ($advanced && $devel_host) { 2773 $fcm->checkbutton(-label => $str_attrib{gBO}->[ATTRIB_PLURAL], 2774 -variable => \$str_draw{'gBO'}, 2775 -command => sub { plot('str', 'gBO') }); 2776 $str_name_draw{"gBO"} = 1; # force drawing of labels 2777 $fcm->checkbutton(-label => defined $city && $city eq 'Berlin' ? M"Berliner Ortsteilnamen" : M"Ortsteilnamen", 2778 -variable => \$str_name_draw{'gBO'}, 2779 -command => sub { 2780 pending(1, 'replot-str-gBO'); 2781 }, 2782 ); 2783 } 2784 if (defined $city && $city eq 'Berlin') { 2785 $fcm->checkbutton(-label => M"Grenzen von Potsdam", 2786 -variable => \$str_draw{'gP'}, 2787 -command => sub { plot('str','gP') }); 2788 } 2789 $fcm->checkbutton(-label => M"Staatsgrenzen", 2790 -variable => \$str_draw{'gD'}, 2791 -command => sub { plot('str','gD') }); 2792 $fcm->checkbutton(-label => M"Grenz�berg�nge", 2793 -variable => \$p_draw{'GU'}, 2794 -command => sub { plot('p', 'GU') }, 2795 ); 2796 2797 menu_entry_up_down($fcm, $tag_group{'str_f'}); 2798 menuright($flaechen_check, $fcm); 2799 menuarrow($fcmb, $fcm, $col++, -special => 'LAYER'); 2800} 2801##### Sehensw�rdigkeiten, Kneipen etc. ##### 2802my $sehenswuerdigkeiten_check; 2803unless ($skip_features{"sehenswuerdigkeiten"}) { 2804 $sehenswuerdigkeiten_check = $misc_frame->$Checkbutton 2805 (image_or_text($star_photo, '*'), 2806 -variable => \$str_draw{'v'}, 2807 -command => sub { plot('str','v') }, 2808 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 2809 $balloon->attach($sehenswuerdigkeiten_check, -msg => M"Sehensw�rdigkeiten etc."); 2810 $ch->attach($sehenswuerdigkeiten_check, -pod => "^\\s*Sehensw�rdigkeiten-Symbol"); 2811 my $knmb = $misc_frame->Menubutton; 2812 my $knm = $knmb->Menu(-title => M"Sehensw�rdigkeiten etc.", 2813 -disabledforeground => $wb->cget(-foreground)); 2814 2815 $knm->checkbutton(-label => M"Sehensw�rdigkeiten", 2816 -variable => \$str_draw{'v'}, 2817 -command => sub { plot('str','v') }); 2818 $knm->command(-label => M"Sehensw�rdigkeit ausw�hlen", 2819 -command => sub { choose_ort(qw(s v), 2820 -markstartifactive => 1) }); 2821 $knm->checkbutton(-label => M"Namen der Sehensw�rdigkeiten", 2822 -variable => \$str_name_draw{'v'}, 2823 -command => sub { 2824 pending(1, 'replot-str-v'); 2825 }, 2826 ); 2827 $knm->checkbutton(-label => M"�berlappungen vermeiden", 2828 -variable => \$no_overlap_label{'v'}, 2829 -command => sub { 2830 pending(1, 'replot-str-v'); 2831 }, 2832 ); 2833 $knm->separator; 2834 2835 $knm->command(-label => M"Pers�nliche Orte", 2836 -command => sub { 2837 require BBBikePersonal; 2838 BBBikePersonal::dialog(); 2839 }); 2840 2841 unless ($skip_features{obst}) { 2842 $knm->checkbutton(-label => M"Obst", 2843 -variable => \$p_draw{'obst'}, 2844 -command => sub { plot('p','obst') }); 2845 } 2846 2847 if ($advanced || $city_obj->is_osm_source) { 2848 my @try_kneipen_list = qw(kn rest ki); 2849 my @kneipen_list; 2850 foreach my $f (@try_kneipen_list) { 2851 if (-f "$datadir/$p_file{$f}") { 2852 push @kneipen_list, $f; 2853 } 2854 } 2855 if (@kneipen_list) { 2856 $knm->separator; 2857 if (!$city_obj->is_osm_source) { 2858 $knm->command(-label => M("Nicht mehr gepflegt").":", 2859 -state => 'disabled', 2860 -font => $font{'bold'}, 2861 ); 2862 } 2863 foreach my $f (@kneipen_list) { 2864 if (-f "$datadir/$p_file{$f}") { 2865 $knm->checkbutton(-label => $p_attrib{$f}->[ATTRIB_PLURAL], 2866 -variable => \$p_draw{$f}, 2867 -command => sub { plot('p',$f) }); 2868 $knm->command(-label => Mfmt("%s ausw�hlen", $p_attrib{$f}->[ATTRIB_SINGULAR]), 2869 -command => sub { choose_ort('p', $f) }); 2870 } 2871 } 2872 } 2873 } 2874 2875 #XXXX menu_entry_up_down($knm, $tag_group{'str_f'}); 2876 menuright($sehenswuerdigkeiten_check, $knm); 2877 menuarrow($knmb, $knm, $col++, -special => 'LAYER'); 2878} 2879##### Zus�tzliche Kartenebenen ##### 2880 my $newlayer_label = $misc_frame->Label 2881 (image_or_text($newlayer_photo, '*'), 2882 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 2883 $balloon->attach($newlayer_label, -msg => M"Zus�tzliche Kartenebenen"); 2884 $ch->attach($newlayer_label, -pod => "^\\s*Zus�tzliche Kartenebenen"); 2885 my $nlmb = $misc_frame->Menubutton; 2886 my $nlm = $nlmb->Menu(-title => M"Zus�tzliche Kartenebenen"); 2887 { 2888 # XXX this used to be LazyMenu to postpone loading of layers 2889 # XXX maybe re-enable this one day if I find a possibility to 2890 # update the cascade menu without showing the menu first. 2891 my $cusm = $nlm; 2892#XXX del: 2893# $BBBike::Menubar::additional_layer_menu = $cusm; 2894# $BBBike::Menubar::additional_layer_menu = $BBBike::Menubar::additional_layer_menu; # peacify -w 2895 $cusm->{BBBike_Menulabel} = M"Zus�tzliche Kartenebenen"; 2896# $opbm->entryconfigure('last', -menu => $cusm); 2897# $cusm->command(-label => M"Zus�tzliche Layer", 2898# -state => 'disabled', 2899# -font => $font{'bold'}); 2900 $cusm->command(-label => M"Stra�en-Layer zeichnen", 2901 -command => sub { 2902 require BBBikeAdvanced; 2903 tk_plot_additional_layer('str') }); 2904 if ($advanced) { 2905 $cusm->command(-label => M"Sperrungen-Layer zeichnen", # XXX label? in advanced mode because there is no way to delete the blockings from net! 2906 -command => sub { 2907 require BBBikeAdvanced; 2908 plot_additional_sperre_layer() }); 2909 } 2910 $cusm->command(-label => M"Punkte-Layer zeichnen", 2911 -command => sub { 2912 require BBBikeAdvanced; 2913 tk_plot_additional_layer('p') }); 2914 $cusm->command(-label => M"Stra�en/Punkte ausw�hlen", 2915 -command => sub { 2916 require BBBikeAdvanced; 2917 choose_from_additional_layer() }); 2918 $cusm->cascade(-label => M("Letzte ge�ffnete Layer")."..."); 2919 { 2920 my $m = $cusm->Menu(-title => M("Letzte ge�ffnete Layer")."..."); 2921 $cusm->entryconfigure("last", -menu => $m); 2922 $last_loaded_layers_obj = 2923 { 2924 List => [], 2925 File => "$main::bbbike_configdir/last_layers", 2926 Menu => $m, 2927 Title => M("Letzte Layer").":", 2928 Cb => sub { 2929 my($file, %args) = @_; 2930 my $linetype = delete $args{-linetype}; 2931 require BBBikeAdvanced; 2932 plot_additional_layer($linetype, $file, %args); 2933 }, 2934 Max => ($devel_host ? 20 : 12), 2935 }; 2936 load_last_loaded($last_loaded_layers_obj); 2937 } 2938 if ($Tk::platform ne 'MSWin32') { 2939 $cusm->command(-label => M"Umordnen", 2940 -accelerator => 'Shift-X', 2941 -command => sub { 2942 require BBBikeAdvanced; 2943 layer_editor() }); 2944 } 2945 $cusm->command(-label => M"Layer l�schen", 2946 -command => sub { 2947 require BBBikeAdvanced; 2948 delete_additional_layer() }); 2949 if ($devel_host) { 2950 $cusm->command(-label => M"Layer in �bersichtskarte zeichnen", 2951 -command => sub { 2952 require BBBikeAdvanced; 2953 tk_draw_layer_in_overview(); 2954 }); 2955 } 2956 $cusm->command(-label => M"Ausschnitt an Layer anpassen", 2957 -command => sub { 2958 require BBBikeAdvanced; 2959 tk_zoom_view_for_layer() }); 2960 $cusm->command(-label => M"Scrollregion an Layer anpassen", 2961 -command => sub { 2962 require BBBikeAdvanced; 2963 tk_set_scrollregion_for_layer() }); 2964 $cusm->command(-label => M"Scrollregion f�r Layer vergr��ern", 2965 -command => sub { 2966 require BBBikeAdvanced; 2967 tk_enlarge_scrollregion_for_layer() }); 2968 if ($advanced) { 2969 $cusm->checkbutton(-label => M"Linienbreite 1 Punkt", 2970 -variable => \$default_line_width, 2971 -offvalue => undef, # XXX don't work, 2972 # set to 0... ??? 2973 -onvalue => 1, 2974 ); 2975 } 2976 $cusm->radiobutton(-label => M"WWW-Klickmodus", # XXX bessere Bezeichnung 2977 -variable => \$map_mode, 2978 -value => MM_URL_SELECT, 2979 -command => \&set_map_mode, 2980 ); 2981 $cusm->separator; 2982 $cusm->command(-label => M"Gpsman-Daten zeichnen", 2983 -command => sub { 2984 draw_gpsman_data($top); 2985 }); 2986 $cusm->cascade(-label => M("Letzte ge�ffnete Tracks/Waypoints")."..."); 2987 { 2988 my $m = $cusm->Menu(-title => M("Letzte ge�ffnete Tracks/Waypoints")."..."); 2989 $cusm->entryconfigure("last", -menu => $m); 2990 $last_loaded_tracks_obj = 2991 { 2992 List => [], 2993 File => "$main::bbbike_configdir/last_tracks", 2994 Menu => $m, 2995 Title => M("Letzte Tracks").":", 2996 Cb => sub { 2997 my($file, %args) = @_; 2998 my %draw_args; 2999 if ($args{-serialized}) { 3000 eval { 3001 require Storable; 3002 require MIME::Base64; 3003 %draw_args = %{ Storable::thaw(MIME::Base64::decode_base64($args{-serialized})) }; 3004 }; 3005 warn $@ if $@; 3006 } 3007 3008 require BBBikeGPS; 3009 BBBikeGPS::do_draw_gpsman_data($top, $file, %draw_args); 3010 }, 3011 Max => ($devel_host ? 20 : 12), 3012 }; 3013 load_last_loaded($last_loaded_tracks_obj); 3014 } 3015 $cusm->command(-label => M"GPS-Track-Animation", 3016 -command => sub { 3017 require BBBikeAdvanced; 3018 gps_animation($top); 3019 }); 3020 } 3021 menuright($newlayer_label, $nlm); 3022 menuarrow($nlmb, $nlm, $col++, -special => 'LAYER'); 3023 3024 # room for plugin buttons 3025 my $mode_layer_plugin_frame = $misc_frame->Frame->grid 3026 (-row => $curr_row, -column => $col, -sticky => 's'); 3027 $top->Advertise(ModeLayerPluginFrame => $mode_layer_plugin_frame); 3028 my $mode_layer_menu_plugin_frame = $misc_frame->Frame->grid 3029 (-row => $curr_row+1, -column => $col, -sticky => 'news'); 3030 $top->Advertise(ModeLayerMenuPluginFrame => $mode_layer_menu_plugin_frame); 3031 $col++; 3032 3033 $misc_frame->Label(-text => ' ')->grid(-row => $curr_row, 3034 -column => $col++); 3035 3036 if (0 && !$no_map) { # no map anymore... 3037 require BBBikeAdvanced; 3038 map_button($misc_frame, $curr_row, \$col); 3039 } 3040 3041###### Vergr��ern ##### 3042 my $mapscale_plus_photo = load_photo($misc_frame, 'viewmag+'); 3043 my $mapscale_plus_button = $misc_frame->Button 3044 (image_or_text($mapscale_plus_photo, '+'), 3045 -command => sub { scalecanvas($c, 2) }, 3046 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 3047 $balloon->attach($mapscale_plus_button, -msg => M"Vergr��ern"); 3048 $ch->attach($mapscale_plus_button, -pod => "^\\s*Vergr��ern-Symbol"); 3049 $col++; 3050 3051###### Verkleinern ##### 3052 my $mapscale_minus_photo = load_photo($misc_frame, 'viewmag-'); 3053 my $mapscale_minus_button = $misc_frame->Button 3054 (image_or_text($mapscale_minus_photo, '-'), 3055 -command => sub { scalecanvas($c, 0.5) }, 3056 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 3057 $balloon->attach($mapscale_minus_button, -msg => M"Verkleinern"); 3058 $ch->attach($mapscale_minus_button, -pod => "^\\s*Verkleinern-Symbol"); 3059 $col++; 3060 3061##### Scale of the map ##### 3062 my $scale_button = $misc_frame->Button 3063 (-textvariable => \$mapscale, 3064 -width => 9, 3065 -relief => 'ridge', 3066 -bd => ($small_icons ? 0 : 2), 3067 -command => sub { enter_scale() }, 3068 -font => $font{'fix15'}, 3069 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 3070 $balloon->attach($scale_button, -msg => M"Ma�stab"); 3071 $ch->attach($scale_button, -pod => "^\\s*Ma�stab-Feld"); 3072 $default_mapscale = calc_mapscale(); 3073 $col++; 3074 3075##### �bersichtskarte 3076 my $berlin_overview_small_photo 3077 = load_photo($top, 'berlin_overview_small'); 3078 my $overview_check = $misc_frame->$Checkbutton 3079 (image_or_text($berlin_overview_small_photo, 'Ovw'), 3080 -variable => \$show_overview, 3081 -command => sub { show_overview() }, 3082 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 3083 $overview_check->bind('<Button-3>' => sub { $show_overview = 1; 3084 show_overview(1) }); 3085 enter_leave_bind_for_help($overview_check, 3086 [M"�bersichtskarte zeigen", 3087 "", 3088 M"�bersichtskarte neu laden", 3089 ]); 3090 3091 $balloon->attach($overview_check, -msg => M"�bersichtskarte"); 3092 $ch->attach($overview_check, -pod => "^\\s*�bersichtskarten-Symbol"); 3093 $col++; 3094 3095 $misc_frame->Label(-text => ' ')->grid(-row => $curr_row, 3096 -column => $col++); 3097 3098##### Windrose ##### 3099 my $windrose_photo = load_photo($misc_frame, 'windrose'); 3100 eval { 3101 die "Low memory" if $lowmem; 3102 require Tk::FireButton; 3103 Tk::FireButton->VERSION(0.04); 3104 }; 3105 my $err = $@; 3106 warn $err if $verbose and $err; 3107 my $firebutton = (!$err ? 'FireButton' : 'Button'); 3108 $windrose_button = $misc_frame->$firebutton 3109 (image_or_text($windrose_photo, "Wind\nrose"), 3110 -command => \&windrose, 3111 -takefocus => 0, 3112 ); 3113 if ($windrose_button->isa('Tk::FireButton')) { 3114 $windrose_button->configure(-repeatinterval => 300); 3115 } 3116 $windrose_button->grid(-row => $curr_row, -column => $col, -rowspan => 2); 3117 $windrose_button->bind("<ButtonPress-2>" => sub { windrose(5) }); 3118 $windrose_button->bind("<ButtonPress-3>" => sub { center_best() }); 3119 enter_leave_bind_for_help($windrose_button, 3120 [M"Karte scrollen", 3121 M"Karte schneller scrollen", 3122 M"Karte zentrieren"]); 3123 $balloon->attach($windrose_button, -msg => M"Kartenausschnitt bewegen"); 3124 $ch->attach($windrose_button, -pod => "^\\s*Windrosen-Symbol"); 3125 $col++; 3126 3127 $misc_frame->Label(-text => ' ')->grid(-row => $curr_row, 3128 -column => $col++); 3129 3130 $top->Advertise(MapFrame => $misc_frame); 3131 3132##### misc_frame2 ... ##### 3133 3134 $misc_frame2 = $sym_frame->$DockFrame 3135 (-bd => 1, -relief => 'raised', 3136 ($DockFrame eq 'DockFrame' ? ('-dock' => $dock_port2) : ())); 3137 $col = 0; 3138 3139##### Komplex: Suche/Route ... ##### 3140 $search_photo = load_photo($misc_frame2, 'search'); 3141 my $search_button = $misc_frame2->$Radiobutton 3142 (image_or_text($search_photo, 'Route'), 3143 -variable => \$map_mode, 3144 -value => MM_SEARCH, 3145 -command => \&set_map_mode, 3146 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 3147 $balloon->attach($search_button, -msg => M"Route suchen"); 3148 $ch->attach($search_button, -pod => "^\\s*Route suchen"); 3149 3150 my $sbmb = $misc_frame2->Menubutton; 3151 my $sbm = $sbmb->Menu(-title => M"Route suchen"); 3152 3153 $sbm->radiobutton(-label => M"Suchmodus", 3154 -variable => \$map_mode, 3155 -value => MM_SEARCH, 3156 -command => \&set_map_mode, 3157 -accelerator => "Shift-S", 3158 ); 3159 $sbm->cascade(-label => M('Route l�schen')); 3160 my $sbm_reset_menu_index = $sbm->index("last"); 3161 3162 $sbm->command(-label => M"Route wiederherstellen (Undo)", 3163 -command =>\&get_undo_route, 3164 -accelerator => 'Ctrl-Z'); 3165 $sbm->command(-label => M"Suche wiederholen", 3166 -command => \&re_search_gui); 3167 $sbm->command(-label => M"R�ckweg", 3168 -command => \&way_back_gui); 3169 $sbm->command(-label => M"Register", 3170 -command => \&show_register, 3171 -accelerator => '*', 3172 ); 3173 $sbm->command(-label => M"Ausschnitt an Route anpassen", 3174 -command => sub { zoom_view() }); 3175 $sbm->cascade(-label => M"Automatische Anpassung"); 3176 { 3177 my $aasm = $sbm->Menu(-title => M"Automatische Anpassung"); 3178 $sbm->entryconfigure('last', -menu => $aasm); 3179 $aasm->checkbutton(-label => M"nach dem Laden anpassen", 3180 -variable => \$zoom_loaded_route, 3181 -onvalue => 1, 3182 -offvalue => 0); 3183 $aasm->checkbutton(-label => M"nach dem Laden zentrieren", 3184 -variable => \$center_loaded_route); 3185 $aasm->checkbutton(-label => M"nach der Berechnung anpassen", 3186 -variable => \$zoom_new_route, 3187 -onvalue => 1, 3188 -offvalue => 0); 3189 $aasm->checkbutton(-label => M"nach der Berechnung aus der Stra�enliste anpassen", 3190 -variable => \$zoom_new_route_chooseort, 3191 -onvalue => 1, 3192 -offvalue => 0); 3193 } 3194 $sbm->separator; 3195 3196 if ($advanced) { 3197 add_search_menu_entries($sbm); 3198 } 3199 if ($advanced || $lowmem) { 3200 $sbm->command(-label => M"Stra�ennetz neu berechnen", 3201 -command => sub { 3202 make_net(); 3203 read_sperre_tragen() unless $lowmem; # XXX should be called automatically, maybe? 3204 }); 3205 $sbm->command(-label => M"undef netz", 3206 -command => sub { 3207 undef $net; 3208 undef $comments_net; 3209 undef $comments_pos_net 3210 }); 3211 } 3212 if ($advanced) { 3213 add_search_net_menu_entries($sbm); 3214 $sbm->separator; 3215 } 3216 3217 unless ($skip_features{"hoehe"}) { 3218 $sbm->checkbutton(-label => M"Steigungen/Gef�lle zeigen", 3219 -variable => \$show_grade); 3220 } 3221 $sbm->cascade(-label => M('Einf�rben der Route').' ...'); 3222 { 3223 my $fbm = $sbm->Menu(-title => M('Einf�rben der Route').' ...'); 3224 $sbm->entryconfigure('last', -menu => $fbm); 3225 foreach my $d ([M"Wind", 'wind'], 3226 [M"Leistung", 'power'], 3227 [M"schwarz", 'black'], 3228 [M"rot", 'red'], 3229 [M"blau", 'blue'], 3230 ) { 3231 my $val = $d->[1]; 3232 $fbm->radiobutton(-label => $d->[0], 3233 -variable => \$coloring, 3234 -value => $val, 3235 -command => \&redraw_path, 3236 ); 3237 } 3238 $fbm->checkbutton(-label => M"gestrichelt", 3239 -variable => \$route_dashed, 3240 -command => \&redraw_path, 3241 ); 3242 $fbm->checkbutton(-label => M"mit Richtungspfeil", 3243 -variable => \$route_arrowed, 3244 -command => \&redraw_path, 3245 ); 3246 $fbm->checkbutton(-label => M"unterhalb liegend", 3247 -variable => \$route_below, 3248 -command => \&redraw_path, 3249 ); 3250 if ($advanced && $devel_host) { 3251 $fbm->command(-label => "spezial gestrichelt", 3252 -command => sub { 3253 # XXX this functionality should probably go into addpoint_xy 3254 for ($c->find("withtag"=>"route")) { $c->createLine($c->coords($_),-fill=>"black",-dash=>[1,3],-tags=>["route"],-width=>$c->itemcget($_,-width)) if $c->type($_) eq "line"} 3255 }); 3256 } 3257 } 3258 3259 $sbm->command 3260 (-label => M"Streckenprofil", 3261 -command => sub { 3262 require BBBikeProfil; 3263 @{$bbbike_context}{qw/Profil Coords Hoehe Transient Canvas/} = 3264 (new BBBikeProfil, 3265 \@realcoords, 3266 \%hoehe, 3267 $transient, 3268 $c); 3269 $bbbike_context->{Profil}->Show($top, $bbbike_context); 3270 }); 3271 require BBBikeVia; 3272 { 3273 $sbm->cascade(-label => M('Start/Via/Ziel').' ...'); 3274 my $viam = $sbm->Menu(-title => M('Start/Via/Ziel').' ...'); 3275 $sbm->entryconfigure('last', -menu => $viam); 3276 BBBikeVia::menu_entries($viam); 3277 } 3278 3279 $sbm->separator; 3280 $sbm->checkbutton(-label => M"Kalorienverbrauch anzeigen", 3281 -variable => \$show_calories, 3282 -command => sub { show_calories() }, 3283 ); 3284 3285 menuright($search_button, $sbm); 3286 menuarrow($sbmb, $sbm, $col++, -menulabel => M"R~oute"); 3287 3288 ##### 3289 3290 $search_pref_photo = load_photo($misc_frame2, 'search_pref'); 3291 my $search_pref_button = $misc_frame2->$Checkbutton 3292 (image_or_text($search_pref_photo, 'Sucheinst.'), 3293 -variable => \$show_enter_opt_preferences, 3294 -command => \&toggle_enter_opt_preferences, 3295 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 3296 $balloon->attach($search_pref_button, -msg => M"Sucheinstellungen"); 3297 $ch->attach($search_pref_button, 3298 -pod => "^\\s*Sucheinstellungen"); 3299 3300 my $sb2mb = $misc_frame2->Menubutton; 3301 my $sb2m = $sb2mb->Menu(-title => M"Sucheinstellungen"); 3302 3303 # Note interplay between these two checkbuttons: 3304 $sb2m->checkbutton(-label => M"Einbahn-/gesperrte Stra�en beachten", 3305 -variable => \$sperre{'sperre'}, 3306 -command => sub { 3307 $sperre{'einbahn'} = $sperre{'wegfuehrung'} = $sperre{'sperre'}; 3308 if (!$sperre{'sperre'}) { 3309 $sperre{'einbahn-strict'} = 0; 3310 } 3311 pending(1, 'recalc-net'); 3312 }, 3313 ); 3314 $sb2m->checkbutton(-label => M"Einbahn-/gesperrte Stra�en *strikt* beachten", 3315 -variable => \$sperre{'einbahn-strict'}, 3316 -command => sub { 3317 if ($sperre{'einbahn-strict'}) { 3318 $sperre{'einbahn'} = $sperre{'wegfuehrung'} = $sperre{'sperre'} = 1; 3319 } 3320 pending(1, 'recalc-net'); 3321 }, 3322 ); 3323 $sb2m->cascade(-label => M"Aktuelle Sperrungen"); 3324 { 3325 my $am = $sb2m->Menu(-title => M"Aktuelle Sperrungen"); 3326 $sb2m->entryconfigure('last', -menu => $am); 3327 $am->checkbutton 3328 (-label => M"Aktuelle Sperrungen zeichnen und beachten", 3329 -variable => \$show_active_temp_blockings, 3330 -command => sub { 3331 activate_temp_blockings($show_active_temp_blockings); 3332 }, 3333 ); 3334 $am->command(-label => M"In dieser Session aktive Sperrungen", 3335 -command => sub { 3336 show_blockings(); 3337 }); 3338 $am->command 3339 (-label => M"Auffrischen der aktuellen Sperrungen", 3340 -command => sub { 3341 gui_activate_temp_blockings(); 3342 }, 3343 ); 3344 if ($advanced) { 3345 $am->separator; 3346 $am->command 3347 (-label => M"Aktuelle und zuk�nftige Sperrungen zeichnen", 3348 -command => sub { 3349 $show_active_temp_blockings = 1; 3350 activate_temp_blockings($show_active_temp_blockings, -from => time); 3351 }, 3352 ); 3353 $am->command 3354 (-label => M"Speichern f�r temp_blockings", 3355 -command => sub { 3356 require BBBikeEdit; 3357 BBBikeEdit::temp_blockings_editor(); 3358 } 3359 ); 3360 $am->separator; 3361 $am->command 3362 (-label => M"Sperrungen zeichnen f�r Datum", 3363 -command => \&active_temp_blockings_for_date_dialog, 3364 ); 3365 $am->command 3366 (-label => M"Fr�here und zuk�nftige Sperrungen zeichnen", 3367 -command => sub { 3368 $show_active_temp_blockings = 1; 3369 activate_temp_blockings($show_active_temp_blockings, -from => 0); 3370 }, 3371 ); 3372 } 3373 } 3374 $sb2m->cascade(-label => M"Benutzerdefinierte Sperrungen"); 3375 { 3376 my $bdm = $sb2m->Menu(-title => M"Benutzerdefinierte Sperrungen"); 3377 $sb2m->entryconfigure('last', -menu => $bdm); 3378 $bdm->radiobutton(-label => M"Definieren", 3379 -variable => \$map_mode, 3380 -value => MM_USEREDIT, 3381 -accelerator => "Shift-U", 3382 -command => sub { # XXX don't duplicate code, see <U> 3383 set_cursor('delnet', 'X_cursor'); 3384 }); 3385 $bdm->command(-label => M"Standard laden", 3386 -command => sub { load_user_dels() }); 3387 $bdm->command(-label => M"Standard speichern", 3388 -command => sub { save_user_dels() }); 3389 $bdm->command(-label => M"Laden", 3390 -command => sub { 3391 my $file = $top->getOpenFile; 3392 if (defined $file) { 3393 load_user_dels($file); 3394 } 3395 }); 3396 $bdm->command(-label => M"Speichern", 3397 -command => sub { 3398 my $file = $top->getSaveFile; 3399 if (defined $file) { 3400 save_user_dels($file); 3401 } 3402 }); 3403 $bdm->command(-label => M"Alle l�schen", 3404 -command => sub { delete_user_dels() }); 3405 if ($advanced) { 3406 $bdm->command(-label => M"In die Zwischenablage kopieren", 3407 -command => sub { 3408 my $s = $net->create_user_deletions_object; 3409 # XXX usage of @inslauf_selection is a hack! 3410 $c->SelectionOwn; 3411 @inslauf_selection = $s->as_string; 3412 }, 3413 ); 3414 } 3415 } 3416 3417 $sb2m->checkbutton(-label => M"Tragen strikt vermeiden", 3418 -variable => \$sperre{'tragen'}, 3419 -command => sub { 3420 pending(1, 'recalc-net'); 3421 }, 3422 ); 3423 $sb2m->checkbutton(-label => M"Schlechte Wege vermeiden", 3424 -variable => \$sperre{'Q3'}, 3425 -command => sub { 3426 pending(1, 'recalc-net'); 3427 },); 3428 unless ($skip_features{faehren}) { 3429 $sb2m->checkbutton(-label => M"F�hren verwenden", 3430 -variable => \$use_faehre, 3431 -command => sub { 3432 pending(1, 'recalc-net'); 3433 }, 3434 ); 3435 } 3436 $sb2m->separator; 3437 $sb2m->checkbutton(-label => M"Stra�enqualit�t-Optimierung", 3438 -variable => \$qualitaet_s_optimierung, 3439 ); 3440 $sb2m->checkbutton(-label => M"Stra�enkategorie-Optimierung", 3441 -variable => \$strcat_optimierung, 3442 -command => sub { 3443 if ($strcat_optimierung) { 3444 $N_RW_optimization = 0; 3445 $N_RW1_optimization = 0; 3446 } 3447 }, 3448 ); 3449 $sb2m->checkbutton(-label => M"Optimierung der sonstigen Beeintr�chtigungen", 3450 -variable => \$handicap_s_optimierung, 3451 ); 3452 $sb2m->checkbutton(-label => M"Ampel-Optimierung", 3453 -variable => \$ampel_optimierung, 3454 -command => \&calc_ampel_optimierung, 3455 ); 3456 $sb2m->checkbutton(-label => M"Radwege-Optimierung", 3457 -variable => \$radwege_optimierung, 3458 -command => sub { 3459 if ($radwege_optimierung) { 3460 $N_RW_optimization = 0; 3461 $N_RW1_optimization = 0; 3462 } 3463 } 3464 ); 3465 $sb2m->checkbutton(-label => M"Hauptstra�en ohne Radwege/Busspuren meiden", 3466 -variable => \$N_RW_optimization, 3467 -command => sub { 3468 if ($N_RW_optimization) { 3469 $radwege_optimierung = 0; 3470 $strcat_optimierung = 0; 3471 $N_RW1_optimization = 0; 3472 } 3473 } 3474 ); 3475 $sb2m->checkbutton(-label => M"Hauptstra�en ohne Radwege meiden", 3476 -variable => \$N_RW1_optimization, 3477 -command => sub { 3478 if ($N_RW1_optimization) { 3479 $radwege_optimierung = 0; 3480 $strcat_optimierung = 0; 3481 $N_RW_optimization = 0; 3482 } 3483 } 3484 ); 3485 unless ($skip_features{"green"}) { 3486 $sb2m->cascade(-label => M("Gr�ne Wege")."..."); 3487 my $gwm = $sb2m->Menu(-title => M"Gr�ne Wege"); 3488 $sb2m->entryconfigure('last', -menu => $gwm); 3489 $gwm->radiobutton(-label => M"egal", 3490 -variable => \$green_optimization, 3491 -value => 0, 3492 ); 3493 $gwm->radiobutton(-label => M"bevorzugen", 3494 -variable => \$green_optimization, 3495 -value => 1, 3496 ); 3497 $gwm->radiobutton(-label => M"stark bevorzugen", 3498 -variable => \$green_optimization, 3499 -value => 2, 3500 ); 3501 } 3502 { 3503 $sb2m->cascade(-label => M("Unterwegs mit")."..."); 3504 my $umm = $sb2m->Menu(-title => M"Unterwegs mit"); 3505 $sb2m->entryconfigure('last', -menu => $umm); 3506 $umm->radiobutton(-label => M"nichts weiter", # XXX expr? 3507 -variable => \$special_vehicle_rb, 3508 -value => 'normal', # used to be $special_vehicle="", but this does not work with Perl/Tk 3509 -command => sub { pending(1, 'recalc-net') }, 3510 ); 3511 $umm->radiobutton(-label => M"Anh�nger", 3512 -variable => \$special_vehicle_rb, 3513 -value => 'trailer', 3514 -command => sub { pending(1, 'recalc-net') }, 3515 ); 3516 $umm->radiobutton(-label => M"Kindersitz mit Kind", 3517 -variable => \$special_vehicle_rb, 3518 -value => 'childseat', 3519 -command => sub { pending(1, 'recalc-net') }, 3520 ); 3521 } 3522 unless ($skip_features{"nolighting"}) { 3523 $sb2m->checkbutton(-label => M"Unbeleuchtete Stra�en meiden", 3524 -variable => \$unlit_streets_optimization, 3525 ); 3526 } 3527 if ($advanced) { # XXX 3528 unless ($skip_features{"tram"}) { 3529 $sb2m->checkbutton(-label => M"Stra�enbahnschienen meiden", 3530 -variable => \$tram_optimization, 3531 ); 3532 } 3533 } 3534 unless ($skip_features{"hoehe"}) { 3535 $sb2m->checkbutton(-label => M"Steigungsoptimierung", 3536 -variable => \$steigung_optimierung, 3537 ); 3538 } 3539 if ($advanced && $devel_host) { 3540 # sowieso vorerst sinnlos... 3541 $sb2m->checkbutton(-label => M"Abbiege-Optimierung", 3542 -variable => \$abbiege_optimierung, 3543 ); 3544 } 3545 $sb2m->separator; 3546 $sb2m->command(-label => M"Optimierungsparameter einstellen", 3547 -command => \&enter_opt_preferences, 3548 ); 3549 if ($advanced) { 3550 # experimenteller Code 3551 $sb2m->command(-label => M"Optimierungsparameter einstellen Nr.2", 3552 -command => \&enter_opt_preferences2, 3553 ); 3554 require BBBikeAdvanced; 3555 penalty_menu($sb2m); 3556 } 3557 3558 menuright($search_pref_button, $sb2m); 3559 menuarrow($sb2mb, $sb2m, $col++, -menulabel => M"~Sucheinstellungen"); 3560 3561 ##### 3562 3563 my $strlist_photo = load_photo($misc_frame2, 'strlist'); 3564 my $strlist_button = $misc_frame2->$Checkbutton 3565 (image_or_text($strlist_photo, 'StrL'), 3566 -variable => \$show_strlist, 3567 -command => sub { show_route_strname() }, 3568 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 3569 $balloon->attach($strlist_button, 3570 -msg => M"Beschreibung der aktuellen Route"); 3571 $ch->attach($strlist_button, 3572 -pod => "^\\s*Beschreibung der aktuellen Route"); 3573 my $slbmb = $misc_frame2->Menubutton; 3574 my $slbm = $slbmb->Menu(-title => M"Beschreibung der aktuellen Route"); 3575 $slbm->checkbutton 3576 (-label => M"Routenliste", 3577 -accelerator => "Shift-B", 3578 -variable => \$show_strlist, 3579 -command => sub { show_route_strname() }, 3580 ); 3581 $slbm->checkbutton 3582 (-label => M"Automatisches Anzeigen", 3583 -variable => \$auto_show_list, 3584 ); 3585 $slbm->command 3586 (-label => M"Statistik", 3587 -command => \&show_statistics, 3588 ); 3589 if ($advanced) { 3590 $slbm->command(-label => M"Ampeln an der aktuellen Route", 3591 -command => sub { ampeln_on_route(@realcoords) }); 3592 $slbm->command(-label => M"GPS-Upload mit Ampelschaltungen", 3593 -command => sub { 3594 require "$FindBin::RealBin/GpsmanDataAmpeln.pm"; 3595 make_ampel_route(); 3596 }); 3597 } 3598 menuright($strlist_button, $slbm); 3599 menuarrow($slbmb, $slbm, $col, -menulabel => M"Routen~liste"); 3600 $col++; 3601 3602 my $reset_photo = load_photo($misc_frame2, 'cross'); 3603 my $reset_button = $misc_frame2->Button 3604 (image_or_text($reset_photo, 'X'), 3605 -command => \&delete_route, 3606 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 3607 $balloon->attach($reset_button, -msg => M"Route l�schen"); 3608 $ch->attach($reset_button, -pod => "^\\s*Route l�schen"); 3609 my $resetmb = $misc_frame2->Menubutton; 3610 my $resetm = $resetmb->Menu(-title => M"Route l�schen"); 3611 $resetm->command(-label => M"Gesamte Route l�schen", 3612 -command => \&delete_route, 3613 -accelerator => 'Ctrl-X', 3614 ); 3615 $resetm->command(-label => M"Letzten Punkt der Route l�schen", 3616 -command => \&mouse_dellast, 3617 -accelerator => '<-', 3618 ); 3619 $resetm->command(-label => M"Bis zum letzten Via l�schen", 3620 -command => \&deltovia, 3621 -accelerator => 'Del', 3622 ); 3623 menuright($reset_button, $resetm); 3624 menuarrow($resetmb, $resetm, $col, -menulabel => M"Route l�schen"); 3625 $col++; 3626 # XXX Check this on Windows! XXX The Tk::Menu manual says: do not 3627 # use "clone" outside of the Tk library! 3628 $sbm->entryconfigure($sbm_reset_menu_index, -menu => $resetm->clone($sbmb, "normal")); 3629 3630 my $reverse_photo = load_photo($misc_frame2, 'rueckweg'); 3631 my $reverse_button = $misc_frame2->Button 3632 (image_or_text($reverse_photo, 'Rev'), 3633 -command => \&way_back_gui, 3634 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 3635 $reverse_button->bind("<ButtonPress-3>" => sub { 3636 IncBusy($top); 3637 eval { 3638 reverse_route(); 3639 }; 3640 DecBusy($top); 3641 }); 3642 $balloon->attach($reverse_button, -msg => M"R�ckweg"); 3643 $ch->attach($reverse_button, -pod => "^\\s*R�ckweg-Symbol"); 3644 $col++; 3645 3646 my $koord_photo = load_photo($misc_frame2, 'koord'); 3647 my $buttonpoint_check = $misc_frame2->$Radiobutton 3648 (image_or_text($koord_photo, 'Koord'), 3649 -variable => \$map_mode, 3650 -value => MM_BUTTONPOINT, 3651 -command => \&set_map_mode, 3652 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 3653 $balloon->attach($buttonpoint_check, -msg => M"Koordinaten in Zwischenablage"); 3654 $ch->attach($buttonpoint_check, -pod => "^\\s*Koordinaten-Symbol"); 3655 3656 my($bpcm); 3657 if (!$advanced) { 3658 $buttonpoint_check->configure(-state => 'disabled'); 3659 } else { 3660 my $bpcmb = $misc_frame2->Menubutton; 3661 $bpcm = $bpcmb->Menu(-title => M"Bearbeiten"); 3662 advanced_coord_menu($bpcm); 3663 menuright($buttonpoint_check, $bpcm); 3664 menuarrow($bpcmb, $bpcm, $col, -menulabel => M"~Bearbeiten"); 3665 } 3666 $col++; 3667 3668 my $info_photo = load_photo($misc_frame2, 'info'); 3669 my $info_check = $misc_frame2->$Radiobutton 3670 (image_or_text($info_photo, 'Info'), 3671 -variable => \$map_mode, 3672 -value => MM_INFO, 3673 -command => \&set_map_mode, 3674 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 3675 $balloon->attach($info_check, -msg => M"Information"); 3676 $ch->attach($info_check, -pod => "^\\s*Info-Symbol"); 3677 $col++; 3678 3679if (!$MM_DRAG_IS_OBSOLETE) { 3680 my $drag_photo = load_photo($misc_frame2, 'movehand'); 3681 my $drag_check = $misc_frame2->$Radiobutton 3682 (image_or_text($drag_photo, 'Drag'), 3683 -variable => \$map_mode, 3684 -value => MM_DRAG, 3685 -command => \&set_map_mode, 3686 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 3687 $balloon->attach($drag_check, -msg => M"Karte verschieben"); 3688 # XXX $ch->attach($drag_check, -pod => "^\\s*Karte verschieben"); 3689 $col++; 3690} 3691 3692 # room for plugin buttons 3693 my $mode_plugin_frame = $misc_frame2->Frame->grid 3694 (-row => $curr_row, -column => $col, -sticky => 's'); 3695 $top->Advertise(ModePluginFrame => $mode_plugin_frame); 3696 my $mode_menu_plugin_frame = $misc_frame2->Frame->grid 3697 (-row => $curr_row+1, -column => $col, -sticky => 'news'); 3698 $top->Advertise(ModeMenuPluginFrame => $mode_menu_plugin_frame); 3699 $col++; 3700 3701 $misc_frame2->Label(-text => ' ')->grid(-row => $curr_row, 3702 -column => $col++); 3703 3704## DEBUG_BEGIN 3705#mymstat("iconframe: load/save/print buttons"); 3706## DEBUG_END 3707##### Komplex: Laden/Speichern/Drucken ##### 3708 my $load_photo = load_photo($misc_frame2, 'open'); 3709 my $load_button = $misc_frame2->Button 3710 (image_or_text($load_photo, 'Load'), 3711 -command => sub { load_save_route(0) } 3712 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 3713 $balloon->attach($load_button, -msg => M"Laden einer Route"); 3714 $ch->attach($load_button, -pod => "^\\s*�ffnen-Symbol"); 3715 my $last_loaded_mb = $misc_frame2->Menubutton; 3716 $last_loaded_menu = $last_loaded_mb->Menu 3717 (-title => M"letzte ge�ffnete Routen", 3718 -disabledforeground => $wb->cget(-foreground)); 3719 menuright($load_button, $last_loaded_menu); 3720 menuarrow($last_loaded_mb, $last_loaded_menu, $col, 3721 -menulabel => M"letzte ge�ffnete Routen", 3722 -special => "OPEN"); 3723 $col++; 3724 3725 my $save_photo = load_photo($misc_frame2, 'save'); 3726 my $save_button = $misc_frame2->Button 3727 (image_or_text($save_photo, 'Save'), 3728 -command => sub { load_save_route(1) } 3729 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 3730 $balloon->attach($save_button, -msg => M"Sichern einer Route"); 3731 $ch->attach($save_button, -pod => "^\\s*Speichern-Symbol"); 3732 my $svmb = $misc_frame2->Menubutton; 3733 my $svm = $svmb->Menu(-title => M"Exportieren", 3734 -disabledforeground => $save_button->cget(-foreground)); 3735 $svm->command(-label => M('Karte speichern als').' ...', 3736 -state => "disabled", 3737 -font => $font{"bold"}); 3738 3739 foreach my $fmt (['PDF', 'pdf'], 3740 ['PNG', 'png'], 3741 ['GIF', 'gif'], 3742 ['JPEG', 'jpeg'], 3743 ['PPM', 'ppm'], 3744 ['Postscript', 'ps'], 3745 ) { 3746 $svm->command(-label => "$fmt->[0]", 3747 -command => sub { 3748 $svm->after(50, sub { export_visible_map($fmt->[1]) }); 3749 }); 3750 if ($fmt->[1] eq 'ps') { 3751 $svm->cascade(-label => M("Postscript-Aufl�sung").' ...'); 3752 my $psm = $svm->Menu(-title => M("Postscript-Aufl�sung").' ...'); 3753 $svm->entryconfigure("last", -menu => $psm); 3754 my(%sizes) = (36 => 0, 72 => 0, 100 => 0, 150 => 0); 3755 $sizes{int($top_dpi)}++; 3756 foreach my $size (sort { $a <=> $b } keys %sizes) { 3757 $psm->radiobutton(-label => $size . " dpi" 3758 . ($size == int($top_dpi) ? " ".M"(normal)" : ""), 3759 -variable => \$ps_image_res, 3760 -value => $size . "x" . $size, 3761 ); 3762 } 3763 } 3764 } 3765 3766 $svm->separator; 3767 $svm->command(-label => M('Route speichern als').' ...', 3768 -state => "disabled", 3769 -font => $font{"bold"}); 3770 foreach my $fmt ( 3771 # GPS 3772 ['GPX (Track)', 'GPX/track'], 3773 'GPX (Route)', 3774 ($advanced ? ['KML (GoogleEarth)', 'KML/track'] : ()), 3775 ['GPSMAN (Track)', 'GpsmanData'], 3776 'GPSMAN (Route)', 3777 ['G7toWin (ASCII)', 'G7toWin_ASCII'], 3778 ['Waypoint+ (Track)', 'WaypointPlus'], 3779 3780 # map/gis 3781 'bbd (BBBike data)', 3782 ($advanced ? ('ESRI') : ()), 3783 # XXX not yet ready: ($devel_host ? ('OVL (TOP50)') : ()), 3784 3785 # vector oriented 3786 'PDF', 3787 'XFig', 3788 ($advanced ? ('SVG') : ()), 3789 3790 '-', 3791 'GPS direkt', 3792 [M('Route zu einem Garmin senden'), 'DirectGarmin'], 3793 [M('Senden der Route zu einem Garmin simulieren'), 'DirectGarmin_Test'], 3794 ($devel_host ? [M("Route mit gpsbabel senden"), "GpsbabelSend"] : ()), 3795 ($devel_host ? [M("Route mit MapSource senden"), "MapSourceSend"] : ()), 3796 ) { 3797 if ($fmt eq '-') { 3798 $svm->separator; 3799 } elsif ($fmt eq 'GPS direkt') { 3800 $svm->command(-label => M($fmt), 3801 -state => "disabled", 3802 -font => $font{"bold"}); 3803 } elsif ($fmt eq 'PDF') { 3804 $svm->command 3805 (-label => $fmt, 3806 -command => \&pdf_export, 3807 ); 3808 } elsif ($fmt eq 'SVG') { 3809 $svm->command 3810 (-label => $fmt, 3811 -command => \&svg_export, 3812 ); 3813 } elsif ($fmt eq 'XFig') { 3814 $svm->command 3815 (-label => $fmt, 3816 -command => sub { 3817 my $file = $top->getSaveFile 3818 (-defaultextension => '.fig', 3819 -filetypes => [[M"FIG-Dateien" => '.fig'], 3820 [M"Alle Dateien" => '*']], 3821 ); 3822 return unless defined $file; 3823 require Tk::CanvasFig; 3824 IncBusy($top); 3825 eval { 3826 mkdir $file."-images", 0755; 3827 $c->fig(-file => $file, 3828 -imagetype => (is_in_path("ppmtopcx") ? 'pcx' : 'xpm'), 3829 -imagedir => $file."-images"); 3830 }; 3831 warn __LINE__ . ": $@" if $@; 3832 DecBusy($top); 3833 }); 3834 } elsif ($fmt =~ /^ovl/i) { 3835 $svm->command 3836 (-label => $fmt, 3837 -command => sub { 3838 require GPS::Ovl; 3839 GPS::Ovl->new->tk_export(coords => \@realcoords); 3840 } 3841 ); 3842 } elsif ($fmt =~ /^bbd/) { 3843 $svm->command 3844 (-label => $fmt, 3845 -command => \&save_route_as_bbd 3846 ); 3847 } elsif ($fmt eq 'GPSMAN (Route)') { 3848 $svm->command 3849 (-label => $fmt, 3850 -command => sub { 3851 gps_interface('BBBikeGPS::GpsmanRoute', -noloading => 1); 3852 }); 3853 } elsif ($fmt eq 'GPX (Route)') { 3854 $svm->command 3855 (-label => $fmt, 3856 -command => sub { save_route_as_optimized_gpx() }, 3857 ); 3858 } elsif ($fmt =~ /^esri/i) { 3859 if (-x "$FindBin::RealBin/miscsrc/bbd2esri" && 3860 -x "$FindBin::RealBin/miscsrc/bbr2bbd" 3861 ) { 3862 $svm->command 3863 (-label => $fmt, 3864 -command => \&save_route_as_esri 3865 ); 3866 } 3867 } elsif (ref $fmt eq 'ARRAY') { 3868 my($label, $module) = @$fmt; 3869 if ($module =~ m{^GPX/(.*)$}) { 3870 my $as = $1; 3871 $svm->command 3872 (-label => $label, 3873 -command => sub { save_route_as_gpx(-as => $as) }, 3874 ); 3875 } elsif ($module =~ m{^KML/(.*)$}) { 3876 my $as = $1; 3877 $svm->command 3878 (-label => $label, 3879 -command => sub { save_route_as_kml(-as => $as) }, 3880 ); 3881 } elsif ($module =~ m{^(GpsbabelSend|MapSourceSend)$}) { 3882 $svm->command 3883 (-label => $label, 3884 -command => sub { 3885 gps_interface('BBBikeGPS::'.$module, -noloading => 1); 3886 }); 3887 } elsif ($module eq 'DirectGarmin') { 3888 $svm->command 3889 (-label => $label, 3890 -command => sub { send_route_to_gps() }, 3891 -accelerator => 'Ctrl-G', 3892 ); 3893 } else { 3894 $svm->command 3895 (-label => $label, 3896 -command => sub { gps_interface($module) }, 3897 ); 3898 } 3899 } else { 3900 warn "XXX SHOULD NOT HAPPEN XXX"; 3901 } 3902 } 3903 3904 menuright($save_button, $svm); 3905 menuarrow($svmb, $svm, $col++, -menulabel => M"Speichern", 3906 -special => 'SAVE'); 3907 3908 my $print_photo = load_photo($misc_frame2, 'printer'); 3909 my $print_button = $misc_frame2->Button 3910 (image_or_text($print_photo, 'Print'), 3911 -command => sub { print_function() }, 3912 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 3913 $balloon->attach($print_button, -msg => M"Drucken der Karte"); 3914 $ch->attach($print_button, -pod => "^\\s*Drucken-Symbol"); 3915 my $prmb = $misc_frame2->Menubutton; 3916 my $prm = $prmb->Menu(-title => M"Druckeinstellungen"); 3917 foreach my $color ([M"Farbe", 'color'], 3918 [M"Graustufen", 'gray'], 3919 [M"Schwarz/Wei�", 'mono'], 3920 ) { 3921 $prm->radiobutton(-label => $color->[0], 3922 -value => $color->[1], 3923 -variable => \$ps_color, 3924 ); 3925 } 3926 $prm->separator; 3927 $prm->radiobutton(-label => M"Landscape", 3928 -value => 1, 3929 -variable => \$ps_rotate, 3930 ); 3931 $prm->radiobutton(-label => M"Portrait", 3932 -value => 0, 3933 -variable => \$ps_rotate, 3934 ); 3935 $prm->separator; 3936 $prm->checkbutton(-label => M"auf A4 skalieren", 3937 -variable => \$ps_scale_a4, 3938 ); 3939 $prm->checkbutton(-label => M"Legende", 3940 -variable => \$use_legend, 3941 ); 3942 $prm->checkbutton(-label => M"Legende rechts statt links", 3943 -variable => \$use_legend_right, 3944 ); 3945 menuright($print_button, $prm); 3946 menuarrow($prmb, $prm, $col++, -menulabel => M"Drucken", 3947 -special => 'PRINT'); 3948 3949 $misc_frame2->Label(-text => ' ')->grid(-row => $curr_row, 3950 -column => $col++); 3951 3952##### Bikepower ##### 3953 my $bike_photo = load_photo($misc_frame2, 'bicycle'); 3954 my $bike_button = $misc_frame2->Button 3955 (image_or_text($bike_photo, 'Bike'), 3956 -command => sub { my %args; 3957 unless (defined $ENV{LANG} && $ENV{LANG} !~ /^de/) { 3958 $args{-lang} = 'de'; 3959 } 3960 $args{-applyhook} = $args{-savedefaultshook} = sub { 3961 # XXX 3962 }; 3963 eval { 3964 my $bp = $bp_obj->tk_interface($top, %args); 3965 set_as_toolwindow($bp); 3966 }; 3967 if ($@) { status_message($@, 'err') } 3968 } 3969 )->grid(-row => $curr_row, -column => $col, -rowspan => 2); 3970 $bike_button->configure(-state => 'disabled') if !$bikepwr; 3971 $balloon->attach 3972 ($bike_button, 3973 -balloonmsg => M"Bikepower", 3974 -statusmsg => M"Bikepower: Eingeben von fahrradspezifischen Daten"); 3975 $ch->attach($bike_button, -pod => "^\\s*Fahrrad-Symbol"); 3976 $col++; 3977 3978 $misc_frame2->Label(-text => ' ')->grid(-row => $curr_row, 3979 -column => $col++); 3980 3981##### Komplex: sonstige Optionen ##### 3982 my $opt_photo = load_photo($misc_frame2, 'opt'); 3983 my $opt_button = $misc_frame2->Button 3984 (image_or_text($opt_photo, 'Opt'), 3985 -command => \&optedit, 3986 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 3987 if (!$opt) { 3988 $opt_button->configure(-state => 'disabled'); 3989 } 3990 $balloon->attach($opt_button, -msg => M"Optionen"); 3991 $ch->attach($opt_button, -pod => "^\\s*Options-Symbol"); 3992 3993 my $opbmb = $misc_frame2->Menubutton; 3994 my $opbm = $BBBike::Menubar::option_menu = $opbmb->Menu(-title => M"Einstellungen"); 3995 $BBBike::Menubar::option_menu = $BBBike::Menubar::option_menu; # peacify -w 3996 # XXX wenn die Save-Funktion funktioniert, folgendes immer ausf�hren: 3997 if ($advanced && $devel_host) { 3998 $opbm->command(-label => M("Konfigurations-Wizard"), 3999 -command => sub { require Wizards; 4000 config_wizard($top); 4001 }); 4002 $opbm->separator; 4003 } 4004 if (0) { 4005 # The portrait/landscape switch is never active. But keep the 4006 # code nevertheless, maybe it will be useful one day if we 4007 # have turnable screen support (but maybe it will be never 4008 # needed) 4009 $opbm->radiobutton(-label => M"Landscape", 4010 -variable => \$orientation, 4011 -value => 'landscape', 4012 -command => sub { 4013 my $replotsub = get_plotted(); 4014 set_landscape(); 4015 $replotsub->(); 4016 }); 4017 $opbm->radiobutton(-label => M"Portrait", 4018 -variable => \$orientation, 4019 -value => 'portrait', 4020 -command => sub { 4021 my $replotsub = get_plotted(); 4022 set_portrait(); 4023 $replotsub->(); 4024 }); 4025 } 4026 if (!$city_obj->is_osm_source) { # no scope with osm data 4027 $opbm->cascade(-label => M('Scope').' ...'); 4028 { 4029 my $sbm = $opbm->Menu(-title => M('Scope').' ...'); 4030 $opbm->entryconfigure('last', -menu => $sbm); 4031 $sbm->command(-label => M"Stadt", 4032 -command => \&city_settings); 4033 $sbm->command(-label => M"n�heres Umland", 4034 -command => \®ion_settings); 4035 unless ($skip_features{wideregion}) { 4036 $sbm->command(-label => M"jwd", 4037 -command => \&jwd_settings); 4038 } 4039 } 4040 } 4041 $opbm->separator; 4042 if (defined $c_balloon) { 4043 $opbm->cascade(-label => M('Canvas balloon').' ...'); 4044 { 4045 my $cbm = $opbm->Menu(-title => M('Canvas balloon').' ...'); 4046 $opbm->entryconfigure('last', -menu => $cbm); 4047 foreach my $d ([M('kein'), 0], 4048 [M('nur Route'), 1], 4049 [M('�berall'), 2]) { 4050 my $val = $d->[1]; 4051 $cbm->radiobutton(-label => $d->[0], 4052 -variable => \$use_c_balloon, 4053 -value => $val, 4054 -command => \&c_balloon_update, 4055 ); 4056 } 4057 } 4058 } 4059 $opbm->command 4060 (-label => M"Farben �ndern", 4061 -command => sub { 4062 require Tk::ColorEditor; 4063 my $cedit = $top->ColorEditor; 4064 $cedit->Show; 4065 }, 4066 ); 4067 $opbm->command 4068 (-label => M"Schriftart �ndern", 4069 -command => sub { change_font() }, 4070 ); 4071 $opbm->checkbutton(-label => M"gedrehte Zeichens�tze", 4072 -variable => \$use_font_rot); 4073 $opbm->checkbutton(-label => M"St�ndige Markierung", 4074 -variable => \$steady_mark, 4075 ); 4076 $opbm->command(-label => M"Markierung l�schen", 4077 -command => \&delete_markers, 4078 ); 4079 $opbm->cascade(-label => M"Mittlere Maustaste"); 4080 { 4081 my $sopbm = $opbm->Menu(-title => M"Mittlere Maustaste"); 4082 $opbm->entryconfigure('last', -menu => $sopbm); 4083 foreach my $val (B2M_NONE, B2M_SCAN, B2M_FASTSCAN, 4084 B2M_AUTOSCROLL, B2M_DELLAST, 4085 ) { 4086 my $label = $b2_mode_desc{$val}; 4087 $label = "???" if (!defined $label); 4088 $sopbm->radiobutton(-label => $label, 4089 -variable => \$b2_mode, 4090 -value => $val, 4091 -command => \&set_b2, 4092 ); 4093 } 4094 } 4095 4096 { 4097 $opbm->cascade(-label => M('Aktualisieren').' ...'); 4098 my $am = $opbm->Menu(-title => M('Aktualisieren').' ...'); 4099 $opbm->entryconfigure("last", -menu => $am); 4100 4101 my $set_immediate_sub = sub { 4102 my($val) = @_; 4103 foreach (qw(replot-str-s replot-str-l 4104 replot-str-qs replot-str-ql 4105 replot-str-hs replot-str-hl 4106 replot-str-r replot-str-b 4107 replot-str-u replot-str-rw 4108 replot-str-v replot-str-f 4109 replot-p-r replot-p-b 4110 replot-p-u 4111 replot-p-o replot-str-w 4112 )) { # XXX weitere replots??? 4113 $immediate{$_} = $val; 4114 } 4115 }; 4116 4117 my $rp; # XXX ein bi�chen hacky (weiter unten) 4118 foreach my $def ([M"Auf Anfrage aktualisieren", 0], 4119 [M"Ausgabe sofort aktualisieren", 1], 4120 [M"Ausgabe verz�gert aktualisieren", 2], 4121 ) { 4122 my $val = $def->[1]; 4123 my $button = $am->radiobutton 4124 (-label => $def->[0], 4125 -variable => \$immediate_replot, 4126 -value => $val, 4127 -command => sub { $set_immediate_sub->($val) }); 4128 $rp = $button if ($val == $immediate_replot); 4129 } 4130 # XXX hier m��ten eigentlich auch die drei Alternativen stehen 4131 my $rc = $am->checkbutton 4132 (-label => M"Netz sofort aktualisieren", 4133 -variable => \$immediate_recalc, 4134 -command => sub { 4135 $immediate{'recalc-net'} = $immediate_recalc; 4136 }, 4137 ); 4138 4139 if ($Tk::VERSION < 803 || $Tk::VERSION >= 804.025) { 4140 $rp->cget(-command)->Call if $rp; 4141 $rc->cget(-command)->Call; 4142 } else { 4143 $rp->cget(-command)->() if $rp; 4144 $rc->cget(-command)->(); 4145 } 4146 $am->command(-label => M"Alles aktualisieren", 4147 -command => sub { update() }); 4148 } 4149 4150### not yet..., see start_followmouse() 4151# $opbm->checkbutton(-label => M"Followmouse", 4152# -variable => \$followmouse, 4153# -command => sub { 4154# if ($followmouse) { 4155# start_followmouse(); 4156# } else { 4157# stop_followmouse(); 4158# } 4159# }, 4160# ); 4161 if ($advanced) { 4162 stderr_menu($opbm); 4163 } 4164 $opbm->checkbutton(-label => M"Wortreich (verbose)", 4165 -variable => \$verbose, 4166 -command => \&set_verbose); 4167 4168 if (!$city_obj->is_osm_source) { 4169 $opbm->command 4170 (-label => M"Daten-Update �ber das Internet", 4171 -command => \&update_via_internet, 4172 ); 4173 } 4174 4175 $opbm->command(-label => M"Alarmliste", 4176 -command => sub { 4177 require BBBikeAlarm; 4178 BBBikeAlarm::tk_show_all(); 4179 }, 4180 ); 4181 4182 if ($advanced && $os ne "win") { 4183 $opbm->command(-label => M"Start BBBike-Server", 4184 -command => sub { gui_start_bbbike_server() }, 4185 ); 4186 } 4187 4188 if (!$standard_menubar) { 4189 plugin_menu($opbm); 4190 } 4191 if ($advanced) { 4192 advanced_option_menu($opbm); 4193 } 4194 menuright($opt_button, $opbm); 4195 menuarrow($opbmb, $opbm, $col++, 4196 -menulabel => M"~Einstellungen", -special => 'OPTIONS'); 4197 4198 my $help_photo = load_photo($misc_frame2, 'help'); 4199 my $help_button = $misc_frame2->Button 4200 (image_or_text($help_photo, '?'), 4201 -command => sub { 4202 eval { 4203 require Tk::Pod; 4204 Tk::Pod->Dir($FindBin::Bin); 4205 $top->Pod(-file => $FindBin::Script . ".pod", 4206 -title => M"Dokumentation zu BBBike"); 4207 }; 4208 if ($@) { 4209 my $r; 4210 my $bbbike_html = Tk::findINC("doc/bbbike.html"); 4211 my $url; 4212 if (defined $bbbike_html && -r $bbbike_html) { 4213 $url = "file:$bbbike_html"; 4214 require WWWBrowser; 4215 $r = WWWBrowser::start_browser($url); 4216 } 4217 if (!$r) { 4218 return if !perlmod_install_advice('Tk::Pod'); 4219 } 4220 } 4221 }, 4222 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 4223 $balloon->attach($help_button, -msg => M"Hilfe"); 4224 $ch->attach($help_button, -pod => "^\\s*Hilfe-Symbol"); 4225 4226 my $hpbmb = $misc_frame2->Menubutton; 4227 my $hpbm = $hpbmb->Menu(-title => M"Hilfe"); 4228 $hpbm->checkbutton(-label => M"Legende", 4229 -command => sub { 4230 toggle_legend($top, -realcanvas => $c); 4231 }, 4232 -variable => \$show_legend, 4233 -accelerator => 'F1'); 4234 my $this_index = $hpbm->index("last"); 4235 $top->bind("<F1>" => sub { $hpbm->invoke($this_index) }); 4236 4237 $hpbm->checkbutton(-label => M"Maushilfe", 4238 -command => \&toggle_mouse_help, 4239 -variable => \$show_mouse_help, 4240 ); 4241 if ($use_contexthelp) { 4242 $hpbm->command(-label => M"Kontexthilfe", 4243 -command => sub { $ch->activate }); 4244 } 4245 my $bbbike_html = Tk::findINC("doc/bbbike.html"); 4246 my $url; 4247 if (defined $bbbike_html && -r $bbbike_html) { 4248 $url = "file:$bbbike_html"; 4249 $hpbm->command 4250 (-label => M"Dokumentation (lokal)", 4251 -command => sub { 4252 require WWWBrowser; 4253 WWWBrowser::start_browser($url); 4254 }); 4255 } 4256 $hpbm->command 4257 (-label => M"Dokumentation (WWW)", 4258 -command => sub { 4259 my $url = "$BBBike::BBBIKE_SF_WWW/bbbike/doc/bbbike.html"; 4260 require WWWBrowser; 4261 WWWBrowser::start_browser($url); 4262 }); 4263 if ($advanced) { 4264 $hpbm->cascade 4265 (-label => M("Mehr Dokumentation")." ..."); 4266 my $m2 = $hpbm->Menu(-title => M("Mehr Dokumentation")." ..."); 4267 $hpbm->entryconfigure("last", -menu => $m2); 4268 for my $doc_def (["doc/links.pod", M"Linkliste"], 4269 ["doc/watchsites.org", M"Watchsites"], 4270 ["doc/qualitaetskategorien.html", M"Qualit�tskategorien"], 4271 ["doc/HOWTO_edit_bbbike_data.html", M"Daten in BBBike editieren"], 4272 ["doc/bbd.pod", M"Beschreibung des bbd-Formats"], 4273 ["doc/tests.pod", M"Manuelle Testanweisung"], 4274 ) { 4275 my($file, $label) = @$doc_def; 4276 my $full_path = $FindBin::RealBin . "/" . $file; 4277 $m2->command 4278 (-label => $label, 4279 -command => sub { 4280 if ($file =~ m{\.pod$}) { 4281 eval { 4282 require Tk::Pod; 4283 }; 4284 if ($@) { 4285 perlmod_install_advice('Tk::Pod'); 4286 } else { 4287 eval { 4288 my $pod = $top->Pod(-file => $full_path, 4289 -title => $label); 4290 set_as_toolwindow($pod); 4291 $toplevel{"pod-$label"} = $pod; 4292 }; 4293 if ($@) { 4294 status_message($@, "die"); 4295 } 4296 } 4297 } elsif ($file =~ m{\.org$}) { 4298 require BBBikeAdvanced; 4299 start_emacsclient("$FindBin::RealBin/$file"); 4300 } else { 4301 require WWWBrowser; 4302 my $url = "file:$full_path"; 4303 WWWBrowser::start_browser($url); 4304 } 4305 }, 4306 ); 4307 } 4308 } 4309 $hpbm->command(-label => M('�ber').' ...', 4310 -command => sub { show_logo('as_about') }); 4311 $hpbm->command(-label => M"Copyright", 4312 -command => sub { copying_viewer($top) }); 4313 $hpbm->command(-label => M"Changes", 4314 -command => sub { simple_file_viewer 4315 ($top, "$FindBin::RealBin/CHANGES", 4316 -title => M"Changes", 4317 -class => "BBBike Changes", 4318 ); 4319 }); 4320 menuright($help_button, $hpbm); 4321 menuarrow($hpbmb, $hpbm, $col++, -menulabel => M"~Hilfe"); 4322 4323 my $context_help_button; 4324 if (!$small_icons) { 4325 # The only reason for the restriction: the image on the button 4326 # is too large. 4327 $context_help_button = 4328 $ch->HelpButton($misc_frame2)->grid 4329 (-row => $curr_row, -column => $col, 4330 -rowspan => 2); 4331 $balloon->attach($context_help_button, -msg => M"Kontexthilfe"); 4332 $col++; 4333 } 4334 4335 if (!$standard_menubar) { 4336 # No need for yet another close button if there's already a 4337 # standard menu: 4338 4339 $misc_frame2->Label(-text => ' ')->grid(-row => $curr_row, 4340 -column => $col++); 4341 4342 my $exit_photo = load_photo($misc_frame2, 'exit'); 4343 my $exit_button = $misc_frame2->Button 4344 (image_or_text($exit_photo, 'Exit'), 4345 -command => \&exit_app, 4346 )->grid(-row => $curr_row, -column => $col, -sticky => 's'); 4347 $balloon->attach($exit_button, -msg => M"BBBike beenden"); 4348 $ch->attach($exit_button, -pod => "^\\s*Ende-Symbol"); 4349 $col++; 4350 } 4351 4352## DEBUG_BEGIN 4353#mymstat("before iconframe: underline all"); 4354## DEBUG_END 4355 if ($misc_frame->can('UnderlineAll')) { $misc_frame->UnderlineAll } 4356 if ($misc_frame2->can('UnderlineAll')) { $misc_frame2->UnderlineAll } 4357 4358 arrange_symframe(); 4359 4360#XXX del: (now in "Aktuelle Route") 4361# $ampelstatus_label = $sym_frame->Label(-justify => "left")->grid 4362# (-row => 0, -column => 2, -sticky => 'n'); 4363 4364## DEBUG_BEGIN 4365#mymstat("before iconframe: bindings"); 4366## DEBUG_END 4367 bind_nomod($top, "<s>" => sub { $strasse_check->invoke}) if $strasse_check; 4368 bind_nomod($top, "<l>" => sub { $landstrasse_check->invoke }) if $landstrasse_check; 4369 bind_nomod($top, "<o>" => sub { $ort_check->invoke }) if $ort_check; 4370 bind_nomod($top, "<u>" => sub { $ubahn_check->invoke }) if $ubahn_check; 4371 bind_nomod($top, "<b>" => sub { $sbahn_check->invoke }) if $sbahn_check; 4372 bind_nomod($top, "<r>" => sub { $rbahn_check->invoke }) if $rbahn_check; 4373 bind_nomod($top, "<w>" => sub { $wasser_check->invoke }) if $wasser_check; 4374 bind_nomod($top, "<f>" => sub { $flaechen_check->invoke }) if $flaechen_check; 4375 bind_nomod($top, "<p>" => sub { $hs_check->invoke }) if $hs_check; 4376 4377 bind_nomod($top, "<R>" => sub { 4378 # Same problems as in <Q>, see below. 4379 if ($str_draw{'l'} || $str_draw{'comm-cyclepath'}) { 4380 $lstrcm->invoke($radwege_l_check_index) if $lstrcm && defined $radwege_l_check_index; 4381 } 4382 if ($str_draw{'s'} || $str_draw{'rw'} || !$str_draw{'l'}) { 4383 $strcm->invoke($radwege_check_index) if $strcm && defined $radwege_check_index; 4384 } 4385 }); 4386 bind_nomod($top, "<a>" => sub { $strcm->invoke($ampeln_check_index) }) if $strcm && defined $ampeln_check_index; 4387 bind_nomod($top, "<g>" => sub { $strcm->invoke($sperre_check_index) }) if $strcm && defined $sperre_check_index; 4388 bind_nomod($top, "<Q>" => sub { 4389 # XXX hmmm... nicht gerade ideal. Beispiel: Landstra�en 4390 # sind aktiv, Q, Stra�en werden aktiv gemacht, Q 4391 # togglet jetzt genau entgegengesetzt... 4392 if ($str_draw{'l'} || $str_draw{'ql'}) { 4393 $lstrcm->invoke($qualitaet_l_check_index) if $lstrcm && defined $qualitaet_l_check_index; 4394 } 4395 if ($str_draw{'s'} || $str_draw{'qs'} || !$str_draw{'l'}) { 4396 $strcm->invoke($qualitaet_check_index) if $strcm && defined $qualitaet_check_index; 4397 } 4398 }); 4399 bind_nomod($top, "<H>" => sub { 4400 # XXX hmmm... nicht gerade ideal. Beispiel: Landstra�en 4401 # sind aktiv, H, Stra�en werden aktiv gemacht, H 4402 # togglet jetzt genau entgegengesetzt... 4403 if ($str_draw{'l'} || $str_draw{'hl'}) { 4404 $lstrcm->invoke($handicap_l_check_index) if $lstrcm && defined $handicap_l_check_index; 4405 } 4406 if ($str_draw{'s'} || $str_draw{'hs'} || !$str_draw{'l'}) { 4407 $strcm->invoke($handicap_check_index) if $strcm && defined $handicap_check_index; 4408 } 4409 }); 4410 bind_nomod($top, '<N>' => sub { $strcm->invoke($nolighting_check_index) }) 4411 if defined $nolighting_check_index; 4412 bind_nomod($top, '<G>' => sub { $strcm->invoke($gruene_wege_check_index) }) 4413 if defined $gruene_wege_check_index; 4414 bind_nomod($top, '<C>' => sub { $c_bpcm->invoke($comments_all_check_index) }) 4415 if defined $comments_all_check_index; 4416 bind_nomod($top, '<V>' => sub { $strcm->invoke($vorfahrt_check_index) }) 4417 if defined $vorfahrt_check_index; 4418 bind_nomod($top, "<question>" => sub { 4419 $strcm->invoke($fragezeichen_check_index) 4420 }) 4421 if defined $fragezeichen_check_index; 4422 bind_nomod($top, "<Y>" => sub { $strcm->invoke($cycle_routes_check_index) }) if $strcm && defined $cycle_routes_check_index; 4423 4424 bind_nomod($top, "<L>" => sub { $lstrcm->invoke($land_jwd_check_index) }) if $lstrcm && defined $land_jwd_check_index; 4425 bind_nomod($top, "<O>" => sub { $ocm->invoke($ort_jwd_check_index) }) if $ocm && defined $ort_jwd_check_index; 4426 bind_nomod($top, "<W>" => sub { $wcm->invoke($wasserumland_check_index) }) if $wcm && defined $wasserumland_check_index; 4427 bind_nomod($top, "<B>" => sub { $strlist_button->invoke }); 4428 4429 # XXX restliche Widgets fehlen noch 4430 for my $w ($strasse_check, $landstrasse_check, $ort_check, 4431 $ubahn_check, $sbahn_check, $rbahn_check, $wasser_check, 4432 $flaechen_check) { 4433 next if !$w; 4434 enter_leave_bind_for_help($w, [M"Option umschalten", '', M"Men�"]); 4435 } 4436 4437} # do_iconframe 4438 4439$splash_screen->Update(0.3, 'load photos') if $splash_screen; 4440 4441##### sonstige Bilder ##### 4442## DEBUG_BEGIN 4443#mymstat("before load photos"); 4444## DEBUG_END 4445load_photos(); 4446 4447my $linestip = eval { Tk::findINC('images/stip.xbm') }; 4448 4449##### configure Canvas/Scrollbars ##### 4450## DEBUG_BEGIN 4451#mymstat("create/config canvas"); 4452## DEBUG_END 4453my $canvas_frame = $frame->Frame->pack(-fill => 'both', -expand => 1); 4454$canvas_frame->gridColumnconfigure(0, -weight => 1); 4455$canvas_frame->gridRowconfigure(0, -weight => 1); 4456 4457$c = $canvas_frame->Canvas 4458 (Name => 'karte', 4459 -bg => $map_bg, 4460 -closeenough => 3, # XXX hmmm ... manchmal gut, manchmal schlect 4461 -scrollregion => \@scrollregion, 4462 #-xscrollincrement => 4, -yscrollincrement => 4, 4463 )->grid(-row => 0, -column => 0, -sticky => 'eswn'); 4464$top->Advertise(Map => $c); 4465$c->{Configure}{-seeview} = \&Tk::Canvas::smooth_scroll; 4466#XXX$c->BindMouseWheel if defined &Tk::Widget::BindMouseWheel; 4467{ 4468 # Re-shuffle bindtags: the "Tk::Canvas" tag is moved from 1st to 4469 # 2nd position. A better solution would be to use a separate class 4470 # for the map canvas. 4471 my @c_bindtags = $c->bindtags; 4472 @c_bindtags = @c_bindtags[1,0,2..$#c_bindtags]; 4473 $c->bindtags([@c_bindtags]); 4474} 4475 4476$sy = $canvas_frame->Scrollbar(-command => ["yview", $c], 4477 -takefocus => 0, 4478 -highlightthickness => 0, 4479 ); 4480$sx = $canvas_frame->Scrollbar(-orient => "horiz", 4481 -command => ["xview", $c], 4482 -takefocus => 0, 4483 -highlightthickness => 0, 4484 ); 4485 4486$c->configure(-yscrollcommand => 4487 sub { $sy->set(@_); 4488 overview_update(); 4489 if (defined &plotstr_on_demand 4490 and $BBBikeLazy::mode) { 4491 my($x1,$y1,$x2,$y2) = $c->get_corners; 4492 plotstr_on_demand(anti_transpose($x1,$y1), 4493 anti_transpose($x2,$y2)); 4494 } 4495 $c_balloon->Deactivate(1) if defined $c_balloon; 4496 }, 4497 -xscrollcommand => 4498 sub { $sx->set(@_); 4499 overview_update(); 4500 if (defined &plotstr_on_demand 4501 and $BBBikeLazy::mode) { 4502 my($x1,$y1,$x2,$y2) = $c->get_corners; 4503 plotstr_on_demand(anti_transpose($x1,$y1), 4504 anti_transpose($x2,$y2)); 4505 } 4506 $c_balloon->Deactivate(1) if defined $c_balloon; 4507 }, 4508 ); 4509 4510## XXX Enable after some rethaught... 4511## XXX and remove the scrollregion code from scalecanvas 4512# for my $hook (qw(after_plot after_resize)) { 4513# Hooks::get_hooks($hook)->add 4514# (sub { 4515# # XXX Is this fast enough? 4516# $c->configure(-scrollregion => [ $c->bbox("all") ]); 4517# }, "bbbike-scrollregion"); 4518# $c->OnDestroy 4519# (sub { 4520# Hooks::get_hooks($hook)->del("bbbike-scrollregion"); 4521# }); 4522# } 4523 4524# Additional MouseWheel bindings 4525$c->Tk::bind("<4>" => [sub { return if $_[1] ne "" && $_[1] ne "B4-"; 4526 $c->yviewScroll(-1,"units") }, 4527 Tk::Ev('s')]); 4528$c->Tk::bind("<5>" => [sub { return if $_[1] ne "" && $_[1] ne "B5-"; 4529 $c->yviewScroll(+1,"units") }, 4530 Tk::Ev('s')]); 4531for ("<Shift-5>", "<B1-5>") { 4532 $c->Tk::bind($_ => sub { $c->xviewScroll(+1,"units") }); 4533} 4534for ("<Shift-4>", "<B1-4>") { 4535 $c->Tk::bind($_ => sub { $c->xviewScroll(-1,"units") }); 4536} 4537$c->Tk::bind('<Control-4>' => sub { scalecanvas_from_canvas_event($c, 2); Tk->break; }); 4538$c->Tk::bind('<Control-5>' => sub { scalecanvas_from_canvas_event($c, 0.5); Tk->break; }); 4539 4540if ($c->can('DropSite')) { 4541 eval { 4542 $c->DropSite 4543 (-dropcommand => [\&accept_drop, $c], 4544 -droptypes => ($os eq 'win' ? 4545 'Win32' : 4546 # KDE is removed from Tk804.02x 4547 [($Tk::VERSION >= 804 ? () : 'KDE'), 'XDND', 'Sun'] 4548 ) 4549 ); 4550 print STDERR M("Datei-DND wird akzeptiert") . "\n" if $verbose; 4551 }; 4552 warn __LINE__ . ": $@" if $@ && $verbose; 4553} 4554 4555# erst hier setzen, weil die Hintergrundfarbe von -xrm und dem Window-System 4556# abh�ngt 4557$category_color{'I'} = $c->cget(-background); 4558 4559standard_selection_handle(); 4560 4561$sy->grid(-row => 0, -column => 1, -sticky => 'ns'); 4562$sx->grid(-row => 1, -column => 0, -sticky => 'ew'); 4563 4564##### Statuszeile/Progress Bar ##### 4565{ 4566 my $status_frame = $frame->Frame(-height => 16)->pack(-fill => 'x'); 4567 # XXX hmmm, das kriege ich nicht so gut hin.... 4568 $status_frame->gridColumnconfigure(0, -weight => 1); 4569 $status_frame->gridColumnconfigure(1, -weight => 5); 4570 $status_frame->gridColumnconfigure(2, -weight => 0); 4571 $status_frame->gridColumnconfigure(3, -weight => 0); 4572 my $gridx = 0; 4573 4574 require Tk::SRTProgress; 4575 Tk::SRTProgress->VERSION(0.06); 4576 $progress = $status_frame->SRTProgress 4577 (-relief => 'sunken', 4578 -borderwidth => 2, 4579 -visible => 0, 4580 -width => $top->width/10, 4581 -labelfont => $font{'reduced'}, 4582 )->grid(-row => 0, 4583 -column => $gridx++, 4584 -sticky => 'ew'); 4585 $status_label = $status_frame->Label(-justify => 'left', -anchor => 'w') 4586 ->grid(-row => 0, -column => $gridx++, -sticky => 'ew'); 4587 4588 $status_button_column = $gridx; 4589 $status_button = $status_frame->Button(-padx => 0, -pady => 0); $gridx++; # do not map 4590 4591 $indicator_frame = $status_frame->Frame 4592 ->grid(-row => 0, -column => $gridx++, -sticky => "ew"); 4593 if ($advanced) { 4594 $edit_mode_type = $indicator_frame->Label 4595 (-text => '', -relief => 'sunken') 4596 ->pack(-side => "left"); 4597 $edit_mode_indicator = $indicator_frame->$Checkbutton 4598 (-text => 'EDIT', 4599 -variable => \$edit_mode_flag, 4600 -command => sub { 4601 set_edit_mode(); 4602 })->pack(-side => "left"); 4603 gui_set_edit_mode($edit_mode); 4604 } 4605 $balloon->configure(-statusbar => $status_label); 4606} 4607 4608use constant UPDATE_FRAC_BEFORE_PLOTTING => 0.4; 4609use constant UPDATE_FRAC_AFTER_PLOTTING => 0.7; 4610 4611$splash_screen->Update(UPDATE_FRAC_BEFORE_PLOTTING, 'start plotting') if $splash_screen; 4612 4613##### initiales Zeichnen ###################################### 4614## DEBUG_BEGIN 4615#BEGIN{mymstat("before init draw BEGIN");} mymstat("before init draw"); 4616## DEBUG_END 4617$progress->InitGroup; 4618 4619###################################################################### 4620# Custom Cursors 4621# Load it before possible use, e.g. in set_edit_mode 4622foreach my $def (qw(start watch ziel addnet delnet info salesman xy 4623 movehand www)) { 4624 load_cursor($def); 4625} 4626if ($cursor{"watch"}) { 4627 $busy_watch_args{-cursor} = ['@' . $cursor{"watch"}, $cursor_mask{"watch"}, 4628 'black', 'white']; 4629} 4630###################################################################### 4631 4632# Read as early as possible; to prevent inconsinstencies especially in lazy mode 4633read_ampeln() unless $lowmem; 4634 4635if (defined $set_mode && $set_mode eq 'edit') { 4636 require BBBikeAdvanced; 4637 set_edit_mode(1); 4638 $init_p_draw{pp} = 1; 4639} 4640# XXX hack: if any of $wasserstadt/umland/... is set, then 4641# $init_str_draw{w} should also be set 4642if ($wasserstadt || $wasserumland || $str_far_away{w}) { 4643 $init_str_draw{w} = 1; 4644} 4645my $_update_steps = ((scalar keys %init_str_draw) + 4646 (scalar keys %init_p_draw)); 4647my $_update_i = 0; 4648foreach (keys %init_str_draw) { 4649 $str_draw{$_} = $init_str_draw{$_}; 4650 eval { 4651 plot('str',$_) if $str_draw{$_}; # Strecken plotten 4652 }; 4653 if ($@ && !$no_original_datadir) { 4654 die $@; 4655 } 4656 $splash_screen->Update((($_update_i++)/$_update_steps)*(UPDATE_FRAC_AFTER_PLOTTING - UPDATE_FRAC_BEFORE_PLOTTING)+UPDATE_FRAC_BEFORE_PLOTTING, "plot str $_") 4657 if $splash_screen; 4658} 4659foreach (keys %init_p_draw) { 4660 $p_draw{$_} = $init_p_draw{$_}; 4661 eval { 4662 plot('p',$_) if $p_draw{$_}; # Punkte (z.B. Ampeln) zeichnen 4663 }; 4664 if ($@ && !$no_original_datadir) { 4665 die $@; 4666 } 4667 $splash_screen->Update((($_update_i++)/$_update_steps)*(UPDATE_FRAC_AFTER_PLOTTING - UPDATE_FRAC_BEFORE_PLOTTING)+UPDATE_FRAC_BEFORE_PLOTTING, "plot p $_") 4668 if $splash_screen; 4669} 4670# H�hen einlesen 4671read_hoehe() if $show_grade || $steigung_optimierung || $use_hoehe; 4672read_sperre_tragen() unless $lowmem; 4673plot_sperre() if $p_draw{'sperre'}; 4674activate_temp_blockings(1) if $do_activate_temp_blockings; 4675 4676if ($net_type =~ /^(us|r|rus|wr)$/) { 4677 make_net(); 4678} 4679 4680if (!$search_route_flag && !(defined $set_mode && $set_mode eq 'edit')) { 4681 search_route_mouse(1); 4682} 4683 4684## DEBUG_BEGIN 4685#BEGIN{mymstat("after init draw BEGIN");} mymstat("after init draw"); 4686## DEBUG_END 4687$progress->FinishGroup; 4688 4689$splash_screen->Update(UPDATE_FRAC_AFTER_PLOTTING, 'finished plotting') if $splash_screen; 4690 4691set_bindings(); 4692 4693$splash_screen->Update(0.8, 'after plotting') if $splash_screen; 4694 4695$last_loaded_obj = 4696 { 4697 List => [], 4698 File => "$bbbike_configdir/last", 4699 Menu => $last_loaded_menu, 4700 Title => M('Letzte Routen-Dateien').':', 4701 Cb => sub { load_save_route(0, $_[0]) }, 4702 Max => 12, 4703 }; 4704load_last_loaded($last_loaded_obj); 4705 4706hide_logo(); 4707if ($top->{initial_iconic}) { 4708 $top->iconify; # may be necessary to undo ->withdraw 4709} else { 4710 $top->deiconify; 4711} 4712 4713scrollregion_best(); 4714 4715# XXX should be after deiconify, otherwise center does not work (?) 4716center_best(); 4717 4718$splash_screen->Update(0.9, 'finalization') if $splash_screen; 4719 4720set_mouse_desc(); 4721 4722if ($map_mode eq MM_SEARCH) { 4723 set_cursor("start"); 4724} 4725 4726if ($preload_file) { 4727 load_save_route(0, $preload_file); 4728} 4729 4730if ($init_from) { 4731 set_route_start_street($init_from); 4732} 4733if ($init_to) { 4734 set_route_ziel_street($init_to); 4735} 4736 4737eval { local $SIG{'__DIE__'}; 4738 require $progname . "_2.config" }; 4739 4740if ($advanced) { 4741 # Besser w�re es, wenn mit "use" die aktuelle Zeit des Moduls 4742 # aufgezeichnet werden k�nnte. So beschr�nke ich mich auf 4743 # minutenweise �berpr�fen, ob neue Module geladen wurden. 4744 check_new_modules(); 4745 $top->repeat(60*1000, \&check_new_modules); 4746} 4747 4748if ($stderr_window) { 4749 require BBBikeAdvanced; 4750 stderr_window_command(); 4751} 4752 4753## DEBUG_BEGIN 4754#BEGIN{mymstat("before mainloop BEGIN");} mymstat("before mainloop"); 4755## DEBUG_END 4756 4757#use Devel::Symdump; 4758#my $symdump = rnew Devel::Symdump; 4759#print $symdump->as_string; 4760 4761if ($use_server and $os ne 'win') { # Win32 unterst�tzt kein fork etc. 4762 require BBBikeServer; 4763 BBBikeServer::create_server($top); 4764} 4765 4766if ($turbo) { 4767 bbbikelazy_init(); 4768} 4769 4770if (defined $initial_plugins && $initial_plugins ne "") { 4771 load_plugins([split /,/, $initial_plugins]); 4772} 4773 4774if (defined $initial_layers && $initial_layers ne "") { 4775 require BBBikeAdvanced; 4776 foreach my $layer_def (split /,/, $initial_layers) { 4777 plot_additional_layer_cmdline($layer_def); 4778 } 4779} 4780 4781if ($splash_screen) { 4782 $splash_screen->Update(1, 'destroying splash'); 4783 $splash_screen->Destroy; 4784 undef $splash_screen; 4785} 4786 4787choose_streets() if $init_choose_street; 4788 4789if ($ENV{BBBIKE_GUI_TEST}) { 4790 eval qq{ 4791 require $ENV{BBBIKE_GUI_TEST}; 4792 \$top->afterIdle(\\&$ENV{BBBIKE_GUI_TEST}::start_guitest); 4793 }; 4794 warn $@ if $@; 4795} 4796 4797if ($init_with_edittools) { 4798 require BBBikeEdit; 4799 BBBikeEdit::init_with_edittools(); 4800} 4801 4802$booting = 0; 4803 4804# Call this after creating the main window, otherwise 4805# bbbike -xrm '*Desk:...' 4806# does not work. 4807$top->afterIdle(sub { 4808 $top->command([$^X, $0]); 4809 }); 4810 4811MainLoop unless $ENV{BBBIKE_TEST_PERFORMANCE}; 4812 4813##### Subs ### RELOADER_START ############################################ 4814 4815sub update_via_internet { 4816 if ($devel_host && $ENV{HOST} !~ /^devpc01/) { 4817 status_message("Kein Update auf biokovo/cabulja/vran/cvrsnica/spiff m�glich!", "die"); 4818 die; 4819 } 4820 my $Dialog = LongOrNormalDialog(); 4821 my $d = $top->$Dialog 4822 (-title => M"Update", 4823 -text => M("Soll das Update gestartet werden?\nJe nach Internet-Verbindung und Stand der Daten kann das Update 5 bis 10 Minuten dauern. Alternativ k�nnen die Dateien als ZIP-Datei von\n$BBBike::BBBIKE_UPDATE_DATA_CGI\ngeholt und in das Verzeichnis\n$FindBin::RealBin/data\nausgepackt werden.\n"), 4824 -bitmap => 'question', 4825 -background => Tk::NORMAL_BG, 4826 -highlightbackground => Tk::NORMAL_BG, 4827 -buttons => [M"Ja", M"Nein"]); 4828 if ($Dialog eq 'LongDialog') { 4829 $d->configure(-height => 10); 4830 } 4831 if ($d->Show eq M"Ja") { 4832 require Update; 4833 Update::bbbike_data_update(); 4834 } 4835} 4836 4837sub telefonbuch_dialog { 4838 my $type = shift; 4839 require Telefonbuch; 4840 my $get_coord = sub { 4841 my($x, $y) = @_; 4842 transpose($x, $y); 4843 }; 4844 my $mark = sub { 4845 my($x, $y, %args) = @_; 4846 my $tcoords = [[]]; 4847 $tcoords->[0][0] = [ transpose($x, $y) ]; 4848 mark_point(-coords => $tcoords, %args, 4849 -clever_center => 1); 4850 }; 4851 if ($type eq 'str') { 4852 Telefonbuch::tk_str_dialog($top, $mark, $get_coord); 4853 } else { 4854 Telefonbuch::tk_tel_dialog($top, $mark, $get_coord); 4855 } 4856} 4857 4858# Berechnet das Layout des obersten Frames neu (z.B. bei einem Resize) 4859sub arrange_topframe { 4860 my(@order) = ($hslabel_frame, $km_frame, $speed_frame[0], 4861 $power_frame[0], $wind_frame, $percent_frame, $temp_frame, 4862 @speed_frame[1..$#speed_frame], 4863 @power_frame[1..$#power_frame], 4864 ); 4865 my(@col) = (0, 1, 3, 4+$#speed_frame, 5+$#speed_frame+$#power_frame, 4866 2, 6+$#speed_frame+$#power_frame, 4867 4..3+$#speed_frame, 4868 5+$#speed_frame..4+$#speed_frame+$#power_frame); 4869 $top->idletasks; 4870 my $width = 0; 4871 my(%gridslaves) = map {($_, 1)} $top_frame->gridSlaves; 4872 for(my $i = 0; $i <= $#order; $i++) { 4873 my $w = $order[$i]; 4874 next unless Tk::Exists($w); 4875 my $col = $col[$i] || 0; 4876 my $reqwidth = $w->reqwidth; 4877 # Special handling for Place/Street label: it shrinks as necessary. 4878 if ($w == $hslabel_frame && $reqwidth > $top->width/3) { 4879 $reqwidth = $top->width/3; 4880 } 4881 $width += $reqwidth; 4882 if ($gridslaves{$w}) { 4883 $w->gridForget; 4884 } 4885 if ($width <= $top->width) { 4886 $w->grid(-row => 0, 4887 -column => $col, 4888 -sticky => 'nsew'); # XXX 4889 } elsif ($devel_host) { # XXX only for debugging, remove one day 4890 require Data::Dumper; 4891 warn "No space for widget\n" . 4892 Data::Dumper->new([$w->class, $w->PathName],[qw(class pathname)])->Indent(1)->Useqq(1)->Dump . 4893 " with i=$i, $width <= " . $top->width; 4894 } 4895 } 4896} 4897 4898# Berechnet das Layout des Symbol-Frames (das die Icons enth�lt) neu 4899sub arrange_symframe { 4900 my($old_row, $new_row); 4901 return unless $misc_frame2 || $DockFrame eq 'DockFrame'; 4902 my $p = $misc_frame2->parent; 4903 if (grep($_ eq $misc_frame2, $p->gridSlaves)) { 4904 # already gridded 4905 my %a = $misc_frame2->gridInfo; 4906 $old_row = $a{-row}; 4907 } else { 4908 # force computation of reqwidth 4909 $misc_frame2->idletasks; 4910 } 4911 my $new_col; 4912 my $is_two_row; 4913 if ($misc_frame->reqwidth + $misc_frame2->reqwidth + 10 4914 > $top->width) { 4915 $new_row = 1; 4916 $new_col = 0; 4917 $is_two_row = 1; 4918 } else { 4919 $new_row = 0; 4920 $new_col = 1; 4921 $is_two_row = 0; 4922 } 4923 if (!defined $old_row || $old_row != $new_row) { 4924 if (defined $old_row) { 4925 $misc_frame2->gridForget; 4926 } 4927 $misc_frame2->grid(-row => $new_row, 4928 -column => $new_col, 4929 -sticky => 'nsw'); 4930 } 4931 4932 # Maybe remove borders between two frames 4933 if ($os eq 'unix' && $devel_host) { # not tested yet on Windows XXX 4934 my $lf = $p->Subwidget("HideLeftBorder"); 4935 my $lc = $p->Subwidget("HideLeftCorner"); 4936 my $rf = $p->Subwidget("HideRightBorder"); 4937 if (!$is_two_row) { 4938 if (!Tk::Exists($rf)) { 4939 $rf = $misc_frame->Frame(-bg => $misc_frame->cget(-bg)); 4940 $p->Advertise("HideRightBorder" => $rf); 4941 } 4942 if (!Tk::Exists($lf)) { 4943 $lf = $misc_frame2->Frame(-bg => $misc_frame->cget(-bg)); 4944 $p->Advertise("HideLeftBorder" => $lf); 4945 } 4946 if (!Tk::Exists($lc)) { 4947 $lc = $misc_frame2->Frame 4948 (-bd => 0, -bg => $misc_frame->Darken($misc_frame->cget(-bg), 60)); 4949 $p->Advertise("HideLeftCorner" => $lc); 4950 } 4951 $lf->place(-rely => 0, -relx => 0, -x => -1, 4952 -width => 1, -relheight => 1); 4953 $lc->place(-rely => 1, -relx => 0, -x => -1, 4954 -width => 1, -height => 1); 4955 $rf->place(-rely => 0, -relx => 1, 4956 -width => 1, -relheight => 1); 4957 } else { 4958 for my $w ($rf, $lf, $lc) { 4959 $w->placeForget if Tk::Exists($w) && $w->manager eq 'place'; 4960 } 4961 } 4962 } 4963} 4964 4965sub handle_options { 4966 @opttable = 4967 (M"Strecken/Punkte", 4968 ['','',M"Strecken und Punkte, die beim Start von BBBike\ngezeichnet werden sollen."], 4969 ['str','!',1, alias=>[qw(strasse strassen)], 4970 label => M"Stra�en", var => \$init_str_draw{'s'}], 4971 ['landstr','!',0, alias=>[qw(landstrasse landstrassen)], 4972 label => M"Landstra�en", var => \$init_str_draw{'l'}], 4973 ['landstrjwd','!',0, 4974 label => M"Landstra�en jwd", var => \$str_far_away{'l'}], # XXX init_str_far_away? 4975 ['sbahn','!',1, 4976 label => M"S-Bahnlinien", var => \$init_str_draw{'b'}], 4977 ['sbahnhof','!',1, 4978 label => M"S-Bahnh�fe", var => \$init_p_draw{'b'}], 4979 ['ubahn','!',1, 4980 label => M"U-Bahnlinien", var => \$init_str_draw{'u'}], 4981 ['ubahnhof','!',1, 4982 label => M"U-Bahnh�fe", var => \$init_p_draw{'u'}], 4983 ['rbahn','!',0, 4984 label => M"R-Bahnlinien", var => \$init_str_draw{'r'}], 4985 ['rbahnhof','!',0, 4986 label => M"R-Bahnh�fe", var => \$init_p_draw{'r'}], 4987 ['wasser','!',1, alias=>[qw(gewaesser)], 4988 label => M"Gew�sser", var =>\$init_str_draw{'w'}], 4989 ['wasserstadt','!',1, 4990 label => M"Gew�sser in der Stadt", var => \$wasserstadt], 4991 ['wasserumland','!',0, 4992 label => M"Gew�sser im Umland", var => \$wasserumland], # XXX auch init! 4993 ['wasserjwd','!',0, 4994 label => M"Gew�sser jwd", var => \$str_far_away{'w'}], 4995 ['faehre','!',0, alias=>[qw(faehren)], 4996 label => M"F�hren", var => \$init_str_draw{'e'}], 4997 ['flaeche','!',1, alias=>[qw(flaechen)], 4998 label => M"Fl�chen", var => \$init_str_draw{'f'}], 4999 ['ort','!',0, alias=>[qw(orte)], 5000 label => M"Orte", var => \$init_p_draw{'o'}], 5001 ['ortsteil','!',0, alias=>[qw(ortsteile)], 5002 label => M"Ortsteile",var => \$init_str_draw{'gBO'}], 5003 ['ortjwd','!',0, 5004 label => M"Orte jwd", var => \$p_far_away{'o'}], 5005 ['sehenswuerdigkeiten','!',0, 5006 label => M"Sehensw�rdigkeiten", var => \$init_str_draw{'v'}], 5007 ['cyclepath', '!',0, alias => [qw(radweg radwege)], 5008 label => M"Radwege", var => \$init_str_draw{'rw'}], 5009 ['cycleroute', '!',0, alias => [qw(radroute radrouten)], 5010 label => M"Radrouten", var => \$init_str_draw{'comm-route'}], 5011 ['greenway', '!',0, alias => [qw(gruenerweg gruenewege)], 5012 label => M"Gr�ne Wege", var => \$init_str_draw{'gr'}], 5013 ['ampel','!',1, alias=>[qw(ampeln|lsa)], 5014 label => M"Ampeln zeichnen", var => \$init_p_draw{'lsa'}], 5015 ['fragezeichen','!',0, 5016 label => M"Fragezeichen", var => \$init_str_draw{'fz'}], 5017 5018 M"Plot-Attribute", 5019 ['outline','!',0, 5020 label => M"Outline zeichnen", var => \$all_outline], 5021 ['lsamaybe','!',undef, nogui => 1, # XXX remove this option??? 5022 label => M"unsichere Ampeln", var => sub { $str_restrict{'lsa'} = {qw(? 1 X 0 B 0 F 0)} }], 5023 ['plothoehe','!',0, 5024 label => M"H�henangaben zeichnen", var => \$init_p_draw{'hoehe'}], 5025 ['showgrade','!',1, 5026 label => M"Anzeige der Steigungen/Gef�lle", var => \$show_grade], 5027 ['grademinimum','=f',0.01, # ab 1% Steigungen/Gef�lle zeigen 5028 label => M"minimal angezeigte Steigung", var => \$grade_minimum], 5029 ['grademinimumshort','=f',0.02, # kurze St�cke erst ab 2% zeigen 5030 label => Mfmt("minimale Steigung (kurze Strecken bis %dm)", $grade_minimum_short_length), var => \$grade_minimum_short], 5031 ['strname','!',0, 5032 label => M"Stra�ennamen plotten", var => \$str_name_draw{'s'}], 5033 ['ubahnname','!',1, 5034 label => M"Namen von U-Bahnh�fen anzeigen", var => \$p_name_draw{'u'}], 5035 ['sbahnname','!',1, 5036 label => M"Namen von S-Bahnh�fen anzeigen", var => \$p_name_draw{'b'}], 5037 ['ortname','!',1, 5038 label => M"Ortsnamen plotten", var => \$p_name_draw{'o'}], 5039 ['ortkategorie','=s','auto', 5040 label => M"Ortskategorie", 5041 longhelp => M"Minimale Ortskategorie, die gezeichnet werden soll", 5042 choices => [qw(auto), MIN_ORT_CAT .. MAX_ORT_CAT], 5043 var => \$place_category], 5044 ['wassername','!',1, alias => [qw(gewaessername)], 5045 label => M"Gew�ssernamen plotten", var => \$str_name_draw{'w'}], 5046 ['rbahnnetz','!',undef, nogui => 1, 5047 label => M"R-Bahnnetz", var => sub { $net_type = "r" }], 5048 ['usbahnetz','!',undef, nogui => 1, 5049 label => M"U/S-Bahnnetz", var => sub { $net_type = "us" }], 5050 ['bahnnetz','!',undef, nogui => 1, 5051 label => M"Gesamtes Bahnnetz", var => sub { $net_type = "rus" }], 5052 ['scope','=s',undef, 5053 label => M"Scope", var => \$init_scope, 5054 choices => ["", qw/city region jwd/]], 5055 ['fast','!',undef, nogui => 1, var => \&fast_settings], 5056 ['turbo','!',undef, nogui => 1, var => sub { fast_settings(); 5057 $turbo = 1; 5058 }, 5059 ], 5060 #XXX -nolazy geht nicht! 5061 ['lazy','!',undef, nogui => 1, var => sub { 5062 $lazy_plot = 1; 5063 # $p_far_away{'o'} = 1; 5064 # $str_far_away{'w'} = 1; 5065 # $str_far_away{'l'} = 1; 5066 # $wasserumland = 1; 5067 # $str_draw{'l'} = $str_draw{'s'}; 5068 # $p_draw{'o'} = 1; 5069 }], 5070 ['lowmem','!',undef, nogui => 1, var => sub { 5071 fast_settings(); 5072 $lowmem = 1; 5073 $use_contexthelp = 0; 5074 $use_balloon = 0; 5075 $use_c_balloon = 0; 5076 $want_wind = 0; 5077 $bikepwr = 0; 5078 @speed = (20); 5079 $init_p_draw{'lsa'} = 0; 5080 $map_color = 'pixmap'; 5081 $show_grade = 0; 5082 $use_hoehe = 0; 5083 }], 5084 ['slowcpu','!',undef, nogui => 1, var => sub { 5085 $slowcpu = 1; 5086 # XXX more 5087 }], 5088 ['center','=s',undef, 5089 label => M"Beim Starten auf Stra�e zentrieren", var => \$center_on_str], 5090 ['centerc','=s',undef, 5091 label => M"Beim Starten auf Koordinaten zentrieren", 5092 widget => sub { 5093 my($self, $frame, $opt) = @_; 5094 my $vref = $self->varref($opt); 5095 my $f2 = $frame->Frame; 5096 $f2->Entry(-textvariable => $vref)->pack(-side => "left"); 5097 $f2->Button(-text => M"Aktueller Kartenausschnitt", 5098 -command => sub { 5099 my(@corner) = $c->get_corners; 5100 my $c_w = ($corner[2]-$corner[0]); 5101 my $c_h = ($corner[3]-$corner[1]); 5102 $$vref = join ",", map { int } anti_transpose($corner[0]+$c_w/2, $corner[1]+$c_h/2); 5103 })->pack(-side => "left"); 5104 $f2; 5105 }, 5106 var => \$center_on_coord], 5107 ['center2c','=s',undef, # XXX currently not really used, but some day may be used together with center_view2 5108 nogui => 1, 5109 var => \$center_on_coord2], 5110 ['choosestreet','!',1, 5111 label => M"Beim Starten Stra�enauswahl zeigen", 5112 var => \$init_choose_street], 5113 ['autoshowlist','!',1, 5114 label => M"Automatisches Anzeigen der Beschreibung", 5115 var => \$auto_show_list], 5116 ['city','=s',undef, 5117 label => M"Stadt", var => \$city, nosave => 1], 5118 ['country','=s',undef, 5119 label => M"Land", var => \$country, nosave => 1], 5120 ['datadir','=s',undef, 5121 label => M"Verzeichnis mit Stra�endaten", 5122 subtype => 'dir', nosave => 1, var => \$datadir], 5123 5124 M"Anzeige", 5125 ['','',M"Bei den meisten Optionen muss BBBike neu gestartet werden,\num die �nderungen sichtbar zu machen."], 5126 ['fontrot','!',1, 5127 label => M"Rotierte Zeichens�tze", var => \$use_font_rot], 5128 ['fontfamily','=s',undef, #'helvetica',#XXX no defaults! 5129 label => M"Zeichensatz (Proportional)", var => \$font_family], 5130 ['fixedfontfamily','=s','courier', 5131 label => M"Zeichensatz (Fixed)", var => \$fixed_font_family], 5132 ['fontheight','=i',undef, #12,#XXX no defaults! 5133 alias => [qw(fontsize)], 5134 label => M"Zeichensatzgr��e", var => \$font_size, 5135 longhelp => M"Negative Gr��en sind in Pixeln, positive in Points", 5136 ], 5137 ['labelfontheight','=i',10, 5138 alias => [qw(labelfontsize)], 5139 label => M"Zeichensatzgr��e f�r Labels", var => \$label_font_size, 5140 longhelp => M"Negative Gr��en sind in Pixeln, positive in Points", 5141 ], 5142 ['fontweight','=s',undef, 5143 label => M"Zeichensatzform", var => \$font_weight], 5144 ['geometry','=s',undef, 5145 subtype => "geometry", # XXX use fix_geometry for tk::getopt editor 5146 label => M"Geometry", var => \$geometry], 5147 ['maximized','!',0, 5148 label => M"immer maximiert �ffnen", var => \$open_maximized], 5149 ['scaling','=f',undef, nogui => 1, 5150 label => M"X11-Skalierung", var => \$scaling], 5151 ['visual','=s',undef, nogui => 1, 5152 label => M"Visual", var => \$visual], 5153 ['scale','=s',undef, 5154 label => M"Skalierung", nogui => 1, 5155 var => \$init_scale_massstab, 5156 ], 5157 ['coloring','=s','red', 5158 label => M"Einf�rben der Route", var => \$coloring, 5159 choices => [qw(red blue black power wind)]], 5160 ['', '', '-'], 5161 ['overviewwasser','!',1, 5162 label => M"�bersichtskarte mit Gew�ssern", var => \$overview_draw{'w'}], 5163 ['overviewsbahn','!',0, 5164 label => M"�bersichtskarte mit S-Bahnen", var => \$overview_draw{'b'}], 5165 ['overviewrbahn','!',0, 5166 label => M"�bersichtskarte mit Regionalbahnen", var => \$overview_draw{'r'}], 5167 ['overviewstr','!',0, 5168 label => M"�bersichtskarte mit Hauptstra�en", var => \$overview_draw{'s'}], 5169 5170 M"GUI", 5171 ['menu','!',1, # XXX hier stand mal "menu|stdmenu|standardmenu" => aber Aliase werden anscheinend von Tk::GetOpt nicht unterst�tzt?! 5172 label => M"Standard-Men�", var => \$standard_menubar, 5173 'callback-interactive' => \&restart_bbbike_hint, 5174 ], 5175 ['balloon','!',1, 5176 label => M"Balloons", var => \$use_balloon, 5177 'callback-interactive' => \&restart_bbbike_hint, 5178 ], 5179 ['cballoon','=i',2, # 0 = nie, 1 = auf der Route, 2 = immer 5180 strict => 1, 5181 choices => [[M"nie" => 0], 5182 [M"nur auf der Route" => 1], 5183 [M"�berall" => 2], 5184 ], 5185 callback => \&c_balloon_update, 5186 label => M"Canvas balloons", var => \$use_c_balloon], 5187 ['cballoonwait','=i',350, 5188 label => M"Wartezeit f�r Canvas balloons", var => \$c_balloon_wait], 5189 ['flat','!',1, 5190 label => M"Flaches Relief", var => \$flat_relief], 5191 ['contexthelp','!',1, 5192 label => M"Kontextsensitive Hilfe", var => \$use_contexthelp], 5193 ['rightispopup','!',1, 5194 label => M"Popup-Men� rechts", var => \$right_is_popup], 5195 ['smoothscroll','!',0, 5196 label => M"Weiches Scrollen", var => \$use_smooth_scroll], 5197 ['followmouse','!',0, 5198 label => M"Kartenausschnitt folgt Cursor", var => \$followmouse], 5199 ['dialog','!',1, 5200 label => M"Verwendung von Dialog-Fenstern", var => \$use_dialog], 5201 ['transient','!',1, 5202 label => M"Transiente Fenster", var => \$transient, 5203 longhelp => M('Verwendung von transienten Fenster oder "Toolwindows"')], 5204 ($os eq 'unix' ? 5205 ['pathentrydialog','!',undef, nogui => 1, 5206 label => M"Alternative Dateiauswahl verwenden", 5207 var => sub { 5208 if (1) { # XXX determine current value --- Tk::GetOpt update necessary 5209 eval 'use Tk::PathEntry::Dialog qw(as_default)'; 5210 } else { 5211 eval 'use Tk::FBox qw(as_default)'; 5212 } 5213 warn $@ if $@; 5214 }, 5215 ] : ()), # do not change dialog on Windows 5216 ['askquit','!',1, 5217 label => M"vor Beenden fragen", var => \$ask_quit], 5218 ['b2mode','=i',B2M_FASTSCAN, nogui => 1, 5219 var => \$b2_mode], 5220 ['autoscroll','!',undef, # XXX make nogui => 0, choices! 5221 label => M"Autoscrolling", nogui => 1, var => sub { $b2_mode = B2M_AUTOSCROLL }], 5222 ['autoscrollspeed','=s','normal', 5223 choices => [qw(slow normal fast)], 5224 label => M"Autoscrolling-Geschwindigkeit", var => \$autoscroll_speed], 5225 ['autoscrollmiddle','!',undef, 5226 label => M"Autoscrollpunkt in der Mitte", var => \$autoscroll_middle], 5227 ['focuspolicy','=s',undef, 5228 label => M"Focus-Policy", 5229 longhelp => 'click:'.M("Click-to-focus")."\n". 5230 'follow:'.M("Focus-follows-mouse")."\n", 5231 var => \$focus_policy, 5232 choices => [qw(click follow)], 5233 ], 5234 5235 M"Suchoptionen", 5236 ['qualitaetoptimierung','!',0, 5237 label => M"Stra�enqualit�t beachten", var => \$qualitaet_s_optimierung], 5238 ['qualitaetwerte','!',{Q0 => 100, 5239 Q1 => 25, 5240 Q2 => 18, 5241 Q3 => 13}, 5242 label => M"Stra�enqualit�t konfigurieren", var => \%qualitaet_s_speed, 5243 nogui => 1], # XXX Tk::Getopt can't handle this yet 5244 ['kategorieoptimierung','!',0, 5245 label => M"Stra�enkategorien beachten", var => \$strcat_optimierung], 5246 ['kategoriewerte','!',{B => 100, 5247 HH => 100, 5248 #BAB => 100, 5249 H => 100, 5250 NH => 100, 5251 N => 100, 5252 NN => 100}, 5253 label => M"Stra�enkategorien konfigurieren", var => \%strcat_speed, 5254 nogui => 1], # XXX Tk::Getopt can't handle this yet 5255 ['radwegeoptimierung','!',0, var => \$radwege_optimierung, 5256 label => M"Radwege-Optimierung"], 5257 ['N_RW_optimization', '!', 0, var => \$N_RW_optimization, nogui => 1],#XXX N_RW vs. N_RW1 missing! 5258 ['tram_optimization', '!', 0, var => \$tram_optimization, nogui => 1], 5259 ['greenoptimierung', '=i', 0, choices => [0,1,2], 5260 longhelp => "0: ".M("egal")."\n". 5261 "1: ".M("bevorzugen")."\n". 5262 "2: ".M("stark bevorzugen")."\n", 5263 label => M"Gr�ne Wege bevorzugen", var => \$green_optimization, 5264 ], 5265 ['unbeleuchtetoptimierung', '!', 0, var => \$unlit_streets_optimization, 5266 label => M"Unbeleuchtete Stra�en meiden"], 5267 ['steigungoptimierung', '!', 0, var => \$steigung_optimierung, 5268 label => M"Steigungsoptimierung"], 5269 ['handicapoptimierung','!',0, 5270 label => M"Sonstige Beeintr�chtigungen beachten", var => \$handicap_s_optimierung], 5271 ['handicapwerte','!',{q0 => 100, 5272 q1 => 25, 5273 q2 => 18, 5274 q3 => 13, 5275 q4 => 5, # z.B. Fu�g�ngerzonen 5276 }, 5277 label => M"Sonstige Beeintr�chtigungen konfigurieren", var => \%handicap_s_speed, 5278 nogui => 1], # XXX Tk::Getopt can't handle this yet 5279 ['sperre','!',undef, alias => [qw(gesperrt)], 5280 label => M"Gesperrte Stra�en beachten", nogui => 1, 5281 var => sub { 5282 $sperre{'einbahn'} = $sperre{'sperre'} = $sperre{'wegfuehrung'} = 1; 5283 }, 5284 savevar => \$sperre{'einbahn'}, 5285 ], 5286 ['einbahn-strict','!',undef, 5287 label => M"Alle Einbahnstra�en *strikt* beachten", nogui => 1, 5288 var => sub { 5289 $sperre{'einbahn-strict'} = 1; 5290 }, 5291 savevar => \$sperre{'einbahn-strict'}, 5292 ], 5293 ['nichttragen','!',0, 5294 label => M"Tragen strikt vermeiden", var => \$sperre{'tragen'}], 5295 ['tempblockings','!',1, 5296 label => M"Aktuelle Sperrungen verwenden", var => \$do_activate_temp_blockings], 5297 ['ampeloptimierung','!',0, 5298 label => M"Ampeloptimierung verwenden", var => \$ampel_optimierung], 5299 ['beschleunigung','=f',1, 5300 label => M"Beschleunigung (m/s^2)", var => \$beschleunigung], 5301 ['wind','!',1, 5302 label => M"Windgeschwindigkeit beachten", var => \$want_wind], 5303 ['faehre','!',0, 5304 label => M"F�hren verwenden", var => \$use_faehre], 5305 ## Without bikepower things like Steigungsoptimierung do not work anymore 5306 #['bikepwr','!',1, alias => [qw(bikepower)], label => M"Bikepower verwenden", var => \$bikepwr], 5307 ['resetpower','!',undef, nogui => 1, var => sub { @power = () }], 5308 ['power','=i@',undef, nogui => 1, var => \@power], # XXX gui => 1 5309 ['resetspeed','!',undef, nogui => 1, var => sub { @speed = () }], 5310 ['speed','=i@',[qw(15 20)], nogui => 1, var => => \@speed], # XXX gui => 1 5311 ['speedpowerreference','=s',undef, nogui => 1, var => \$speed_power_reference_string], 5312 ['from','=s',undef, nogui => 1, -var => \$init_from], 5313 ['to','=s',undef, nogui => 1, -var => \$init_to], 5314 5315 M"WWW", 5316 ['www','!',0, # 1, wenn Wetterdaten vom Web geholt werden sollen 5317 label => M"WWW verwenden", var => \$do_www], 5318 (0&&$devel_host ? 5319 ( 5320 ['wwwmap','!',undef, 5321 label => M"Karten �bers WWW holen", var => \$do_wwwmap], 5322 ['wwwcache','!',0, 5323 label => M"Cache f�r WWW-Karten verwenden", var => \$use_wwwcache], 5324 ) : () 5325 ), 5326 ['proxy','=s', undef, 5327 label => M"HTTP-Proxy (Format: http://host:port/)", var => \$proxy], 5328 ['cachedir','=s',undef, 5329 label => M"Cacheverzeichnis", subtype => 'dir', 5330 var => \$cache_root], 5331 5332 M"GPS", 5333 ['exporttxtmode','=i',EXPORT_TXT_SIMPLIFY_AUTO, 5334 label => M"Vereinfachung von Routen", 5335 longhelp => M"GPS-Ger�te k�nnen nur eine begrenzte Anzahl von Waypoints pro Route verwenden. 5336Eine von BBBike berechnete Route erzeugt meist mehr Waypoints. 5337Mit dieser Option kann eingestellt werden, welche Strategie 5338dazu verwendet wird", 5339 choices => [[M("Komplette Route"), EXPORT_TXT_FULL], 5340 [M("Unterschiedliche Stra�ennamen"), EXPORT_TXT_SIMPLIFY_NAME], 5341 [M("Abbiegevorg�nge"), EXPORT_TXT_SIMPLIFY_ANGLE], 5342 [M("Abbiegevorg�nge/unterschiedliche Stra�ennamen"), EXPORT_TXT_SIMPLIFY_NAME_OR_ANGLE], 5343 [M("automatisch"), EXPORT_TXT_SIMPLIFY_AUTO], 5344 ], 5345 strict => 1, 5346 var => \$export_txt_mode], 5347 ['exporttxtminangle','=s',30, 5348 choices => [5,15,30,45,60], 5349 label => M"Minimalwinkel bei Route-Vereinfachung", 5350 longhelp => M"Minimalwinkel in Grad bei der Vereinfachung von Routen\n", 5351 var => \$export_txt_min_angle], 5352 ['gpswaypoints','=i',50, 5353 choices => [20,50,100,250], 5354 label => M"Maximale Anzahl der GPS-Waypoints", 5355 longhelp => M"Moderne Garmin-Ger�te wie der eTrex Vista HCx k�nnen 250 Waypoints pro Route verwenden,\netwas �ltere wie der eTrex Vista 50 Waypoints,\nw�hrend noch �ltere nur 20 Waypoints laden k�nnen\n", 5356 var => \$gps_waypoints, 5357 ], 5358 ['gpswaypointlength','=i',10, 5359 choices => [10, 14, 20], 5360 label => M"Maximale L�nge von GPS-Waypoint-Namen", 5361 longhelp => M"Typischerweise 10 bei �lteren Garmin-Ger�ten, aber neuere Ger�te k�nnen l�ngere Namen verwenden (eTrex Vista HCx z.B. offiziell 14 Zeichen, tats�chlich sogar 20 Zeichen)", 5362 var => \$gps_waypointlength, 5363 ], 5364 ['gpswaypointcharset','=s','simpleascii', 5365 label => 'Zeichensatz f�r Waypoints', 5366 strict => 1, 5367 choices => [['Nur Gro�buchstaben' => 'simpleascii'], 5368 ['Gro�/Kleinbuchstaben' => 'ascii'], 5369 ['Gro�/Kleinbuchstaben, Umlaute' => 'latin1'], 5370 ], 5371 var => \$gps_waypointcharset, 5372 ], 5373 ['gpswaypointsymbol','=i','', 5374 label => M"Waypointsymbol", 5375 longhelp => M"Garmin-Symbol-ID. Falls leer gelassen, wird das Summit-Symbol verwendet", 5376 var => \$gps_waypointsymbol, 5377 ], 5378 ['gpsneeduniqueroutenumber','!',0, 5379 label => M"GPS-Ger�t ben�tigt eindeutige Routennummern", 5380 longhelp => M"Laut Garmin-Spezifikationen m�ssen �betragene Routen mit einer eindeutigen Routennummer versehen werden.\nExperimente haben aber gezeigt, dass die meisten (oder alle?) Garmin-Ger�te dieses nicht ben�tigen.", 5381 var => \$gps_needuniqueroutenumber, 5382 ], 5383 ['gpsdevice','=s',($os eq 'win' ? "USB" : 5384 $os_bsd ? '/dev/cuaa0' : 5385 $^O eq 'linux' ? '/dev/ttyUSB0' 5386 : '/dev/ttyS0' 5387 ), 5388 choices => ( $os eq 'win' ? ["USB", (map { "COM$_" } (1..4))] 5389 : $os_bsd ? [map { "/dev/cuaa$_" } (0..3) ] 5390 : [map { ($_."0", $_."1", $_."2", $_."3") } ("/dev/ttyUSB", "/dev/usb/ttyUSB", "/dev/tts/USB", "/dev/ttyS") ] 5391 ), 5392 label => M"GPS-Device", var => \$gps_device], 5393 5394 M"Sonstiges", 5395 ['kde','!',undef, 5396 label => M"F�r KDE optimieren", var => \$run_under_kde], 5397 ['handheld','!',undef, 5398 label => M"F�r kleine Bildschirme optimieren", var => \$is_handheld, 5399 longhelp => M"F�r kleine Bildschirme (Handhelds, PDAs, mobile Telefone) optimieren. Bei dieser Einstellung werden kleine Symbole verwendet und das normale Men� wird entfernt", 5400 ], 5401 ['coordout','=s','standard', 5402 label => M"Koordinatenausgabe", var => \$coord_output], 5403 ['printcmd','=s',undef, 5404 label => M"Druckerkommando", var => \$print_cmd], 5405 ['printbackend','=s',undef, 5406 label => M"Druck-Backend", var => \$print_backend, 5407 choices => ["", qw(ps pdf)], 5408 ], 5409 ['ps_fixed_font','=s',"Courier7", 5410 label => M"Druckerzeichensatz (fixed)", var => \$ps_fixed_font], 5411 ['mapcolor','=s','color', 5412 choices => [qw(mono pixmap gray color)], 5413 label => M"Farbeinstellung beim Drucken", var => \$map_color], 5414 ['gvreuse','!',0, # 1: alten gv-Prozess wiederverwenden 5415 label => M"GV-Fenster wiederverwenden", var => \$gv_reuse], 5416 ['server','!',undef, 5417 label => M"Server-Modus", var => \$use_server], 5418 ['autosave','!',1, 5419 label => M"Speichern beim Beenden", var => \$autosave_opts], 5420 ['environment','=s','normal', 5421 # "novacom" (f�r GDF-Daten als Standard) 5422 # "onlineoffice" (f�r Onlineoffice-Pr�sentationen) 5423 nogui => 1, var => \$environment], 5424 ['mldbm','!',0, 5425 label => M"Verwendung von MLDBM", 5426 longhelp => M"Die interne Stra�ennetz-Struktur wird als MLDBM-Hash 5427auf der Festplatte statt im RAM gehalten. Langsamer, aber 5428speicherplatzsparender.", 5429 var => \$use_mldbm], 5430 ['palmdocfmt','=s','isilo', 5431 choices => [qw(isilo pdbdoc)], 5432 label => M"Palm-Doc-Format", var => \$palm_doc_format], 5433 ['usexwd','!',undef, 5434 label => M"xwd als Screengrabber", var => \$use_xwd_if_possible], 5435 5436 M"Advanced", 5437 ['edit','!',undef, 5438 label => M"Editmodus beim Starten", 5439 nogui => 1, # XXX remove some day? 5440 var => sub { 5441 $set_mode = "edit"; 5442 } 5443 ], 5444 ['edittools','!',undef, 5445 label => M"Editierwerkzeuge beim Starten �ffnen", 5446 nogui => 1, # XXX remove some day? 5447 var => \$init_with_edittools, 5448 ], 5449 ['texteditor','=s',undef, 5450 label => M"Externer Texteditor", 5451 var => \$texteditor, 5452 longhelp => M"M�gliche Werte sind vi (automatisch in einem xterm gestartet), emacsclient, gnuclient", 5453 ], 5454 ['stderr','!',0, 5455 label => M"Fehlerausgabe auf stderr", var => \$stderr], 5456 ['stderrwindow','!',undef, 5457 label => M"STDERR in ein Fenster", var => \$stderr_window], 5458 ['autoinstall','!',0, 5459 label => M"Auto-Installation vom CPAN (experimentell!)", var => \$auto_install_cpan], 5460 ['pp','!',0, 5461 label => M"Kurvenpunkte und Kreuzungen zeichnen", var => \$init_p_draw{'pp'}, nosave => 1, nogui => 1], 5462 ['advanced','!',undef, var => \$advanced, 5463 label => M"Advanced mode"], 5464 ['public','!',undef, nogui => 1, 5465 var => \&_set_public], 5466 ['publicconfig','!',undef, nogui => 1, 5467 var => \&_set_public], 5468 ['configfile','=s',undef, nogui => 1], # used only in pre_check_arguments 5469 ['v','!',0, alias => [qw(verbose)], 5470 label => M"Verbose", var => \$verbose, 5471 longhelp => M"Die Variable \$verbose kann manuell auf 2 oder h�her gesetzt werden, um die Anwendung wortreicher zu machen"], 5472 ['version','!',undef, 5473 nogui => 1, var => sub { 5474 my %git_info; 5475 if (-r "$FindBin::RealBin/miscsrc/BBBikeGit.pm") { 5476 require "$FindBin::RealBin/miscsrc/BBBikeGit.pm"; 5477 %git_info = BBBikeGit::git_info(); 5478 } 5479 print("$progname $VERSION\n", 5480 ($git_info{patchnum} ? "(patchnum $git_info{patchnum})\n" : ''), 5481 "perl $]\nTk $Tk::VERSION\n", 5482 ); 5483 CORE::exit(0); 5484 }], 5485 ['plugins','=s',undef, 5486 label => M"Plugins beim Starten laden", var => \$initial_plugins, 5487 longhelp => M"Kommaseparierte Liste von Plugins, z.B. BBBikeThunder,BBBikeSalesman,BBBikeRuler", # XXX Auf den PluginLister verweisen, wenn er fertig ist. 5488 widget => sub { 5489 my $self = shift; 5490 my $frame = shift; 5491 my(@args) = @_; 5492 my $f = $frame->Frame; 5493 $self->_string_widget($f, @args)->pack(-side => "left"); 5494 $f->Button(-text => M"Plugin-Lister", 5495 -padx => 1, 5496 -pady => 1, 5497 -command => sub { 5498 require BBBikePluginLister; 5499 BBBikePluginLister::plugin_lister($top, $FindBin::RealBin); 5500 })->pack(-side => "left"); 5501 $f; 5502 }, 5503 ], 5504 ['layers','=s',undef, 5505 label => M"Zus�tzliche Layer zeichnen", var => \$initial_layers], 5506 ['algorithm','=s','A*', var => \$global_search_args{Algorithm}, 5507 longhelp => M"Nur A* (Perl-Implementation) und C-A* (C-Implementation) sind von Interesse", 5508 choices => ['A*', 'C-A*', ($devel_host||$advanced ? ("C-A*-2", 'srt') : ())], 5509 label => M"Suchalgorithmus", 5510 strict => 1], 5511 ['h','!',undef, nogui => 1, alias => [qw(help)], 5512 var => sub { 5513 if ($opt) { 5514 print STDERR $opt->usage; 5515 } else { 5516 die M"Usage?"; 5517 } 5518 exit(0); 5519 }], 5520 ['nosplash','!',undef, nogui => 1], # pseudo option, handled at BEGIN 5521 ); 5522 5523 eval { 5524 require Tk::Getopt; 5525 Tk::Getopt->VERSION(0.4951); 5526 }; 5527 if ($@) { # XXX 5528 die "Please report to author: use opttable_to_getopt!!!! XXX"; 5529 warn __LINE__ . ": $@" if $verbose; 5530 my @getopt_list; 5531 foreach (@getopt) { 5532 push @getopt_list, $_ unless /^=/; 5533 } 5534 # XXX '@' geht nur mit Getopt::Long 5535 push @getopt_list, 'power=i@' => \@power, 'speed=i@' => \@speed; 5536 require Getopt::Long; 5537 #XXX X11-Optionen durchschleifen... 5538 # if (!Getopt::Long::GetOptions(@getopt_list)) { usage('', \@getopt_list) } 5539 Getopt::Long::config('pass_through'); 5540 Getopt::Long::GetOptions(@getopt_list); 5541 #XXX if (!GetOptions(@getopt_list)) { usage('', \@getopt_list) } 5542 } else { 5543 $Tk::Getopt::x11_pass_through = 1; 5544 pre_check_arguments(); # sets $public 5545# $opt = Tk::Getopt->new 5546 $opt = My::Tk::Getopt->new 5547 (-opttable => \@opttable, 5548 -filename => defined $config_file ? $config_file : catfile($bbbike_configdir, ($public ? "config_publictest" : "config")), 5549 -useerrordialog => 1, 5550 ); 5551 $opt->set_defaults; 5552 $opt->load_options if !$public || $public_config; # force defaults 5553 if (!$opt->get_options) { 5554 print $opt->usage; 5555 exit 1; 5556 } 5557 $opt->process_options; 5558 } 5559 Tk::CmdLine::SetArguments(); # XXX here correct position? 5560 if (@ARGV) { 5561 require Getopt::Long; 5562 Getopt::Long::config('nopass_through'); 5563 Getopt::Long::GetOptions() or die; 5564 } 5565} 5566 5567sub _set_public { 5568 $public_test = 1; 5569 $advanced = 0; 5570 $devel_host = 0; 5571 $do_www = 0; 5572 $no_map = 1; 5573 $public = 1; 5574 $autosave_opts = 0; 5575 $lazy_plot = 0; 5576 undef $proxy; 5577 # Not in old standard Tk: 5578 if ($Tk::VERSION < 804) { 5579 $can_handle_image{png} = 0; 5580 $can_handle_image{jpg} = 0; 5581 } 5582} 5583 5584sub c_balloon_update { 5585 if ($c_balloon && Tk::Exists($c_balloon)) { 5586 $c_balloon->configure(-show => $use_c_balloon); 5587 } 5588} 5589 5590# Check for -public and -publicconfig options --- in this case do not 5591# load the config file. 5592sub pre_check_arguments { 5593 for(my $arg_i=0; $arg_i<=$#ARGV; $arg_i++) { 5594 my $arg = $ARGV[$arg_i]; 5595 if ($arg eq '-public') { 5596 $public = 1; 5597 } elsif ($arg eq '-publicconfig') { 5598 $public = 1; 5599 $public_config = 1; 5600 } elsif ($arg eq '-configfile') { 5601 $config_file = $ARGV[$arg_i+1]; 5602 die "Expected argument for -configfile option" if !$config_file; 5603 $arg_i++; 5604 } 5605 } 5606} 5607 5608# For binding plain keybindings without modifiers 5609sub bind_nomod { 5610 my($top, $ev, $cb) = @_; 5611 $top->bind 5612 ($ev, sub { 5613 my $w = shift; 5614 my $e = $w->XEvent; 5615 # auf Alt, Control und CapsLock checken 5616 # bei Win95/NT ist 8 nicht CapsLock, sondern NumLock 5617 if ($Tk::VERSION < 800) { 5618 return if $e->s & (1+($os eq 'win' ? 0 : 8)); # XXX control is missing ... 4? 2 ist Shift? 5619 } else { 5620 return if $e->s =~ /\b(Alt|Lock|Control)-/; 5621 } 5622 $cb->($w, @_); 5623 }); 5624} 5625 5626# km <=> m (<=> mi) 5627sub change_unit { 5628 my $new_unit = shift; 5629 if (defined $new_unit) { 5630 $unit_s = $new_unit; 5631 } elsif ($Msg::lang eq 'en') { 5632 $unit_s = ($unit_s eq 'km' ? 'mi' : 5633 $unit_s eq 'mi' ? 'm' : 5634 'km'); 5635 } else { 5636 $unit_s = ($unit_s eq 'km' ? 'm' : 'km'); 5637 } 5638 updatekm(); 5639} 5640 5641sub standard_selection_handle { 5642 $c->SelectionHandle 5643 (sub { 5644 my($offset, $maxbytes) = @_; 5645 my($inslauf) = join(" ", @inslauf_selection); 5646 return undef if $offset > length($inslauf); 5647 substr($inslauf, $offset, $maxbytes); 5648 }); 5649} 5650 5651sub load_photos { 5652 # Note that some rarely used photos are loaded on-demand. 5653 $flag_photo{'start'} = load_photo($top, 'flag2_bl_centered'); 5654 $flag_photo{'via'} = load_photo($top, 'flag_via_centered'); 5655 $flag_photo{'ziel'} = load_photo($top, 'flag_ziel_centered'); 5656 $ampel_photo = load_photo($top, 'ampel'); 5657 $ampel_klein2_photo = load_photo($top, 'ampel_klein2'); 5658 $ampelf_photo = load_photo($top, 'ampelf'); 5659 $ampelf_klein_photo = load_photo($top, 'ampelf_klein'); 5660 $ampelf_klein2_photo = load_photo($top, 'ampelf_klein2'); 5661 $andreaskr_klein_photo = load_photo($top, 'andreaskr_klein'); 5662 $andreaskr_klein2_photo= load_photo($top, 'andreaskr_klein2'); 5663 $andreaskr_photo = load_photo($top, 'andreaskr'); 5664 $andreaskr_grey_klein_photo = load_photo($top, 'andreaskr_klein', -palette => 256); 5665 $andreaskr_grey_klein2_photo= load_photo($top, 'andreaskr_klein2', -palette => 256); 5666 $andreaskr_grey_photo = load_photo($top, 'andreaskr', -palette => 256); 5667 $kreisverkehr_photo = load_photo($top, 'kreisverkehr'); 5668 $windrose2_photo = load_photo($top, 'windrose2'); 5669 $kneipen_photo = load_photo($top, 'glas'); 5670 $kneipen_klein_photo = load_photo($top, 'glas_klein'); 5671 $essen_photo = load_photo($top, 'essen'); 5672 $essen_klein_photo = load_photo($top, 'essen_klein'); 5673 $kino_klein_photo = load_photo($top, 'kino_klein'); 5674 $steigung_photo = load_photo($top, 'steigung'); 5675 $gefaelle_photo = load_photo($top, 'gefaelle'); 5676 $inwork_photo = load_photo($top, 'inwork_18'); 5677 $inwork_klein_photo = load_photo($top, 'inwork_12'); 5678 $achtung_photo = load_photo($top, 'achtung'); 5679 $cal_photo = load_photo($top, 'cal'); 5680 $cal_questionmark_photo = load_photo($top, 'cal_questionmark'); 5681 $clock_photo = load_photo($top, 'clock'); 5682 $night_photo = load_photo($top, 'night'); 5683 $ferry_photo = load_photo($top, 'ferry') 5684 if !$ferry_photo; 5685 $ferry_klein_photo = load_photo($top, 'ferry_klein'); 5686 $ferry_mini_photo = load_photo($top, 'ferry_mini'); 5687 $zugbruecke_photo = load_photo($top, 'zugbruecke'); 5688 $zugbruecke_klein_photo 5689 = load_photo($top, 'zugbruecke_klein'); 5690 $notrailer_photo = load_photo($top, 'notrailer'); 5691#XXX not yet necessary: 5692# $blocked_photo = load_photo($top, 'redcross'); 5693} 5694 5695sub set_default_geometry { 5696 if ($geometry && !$open_maximized) { 5697 @want_extends = parse_geometry_string($geometry); 5698 if (!$want_extends[GEOMETRY_WIDTH] || !$want_extends[GEOMETRY_HEIGHT]) { # test on 0 or undef 5699 ($want_extends[GEOMETRY_WIDTH], $want_extends[GEOMETRY_HEIGHT]) = 5700 ($top->screenwidth, $top->screenheight); 5701 } 5702 if (!defined $want_extends[GEOMETRY_X] || !defined $want_extends[GEOMETRY_Y]) { 5703 ($want_extends[GEOMETRY_X], $want_extends[GEOMETRY_Y]) = (0, 0); 5704 } 5705 } else { 5706 @want_extends = (0, 0, $top->screenwidth, $top->screenheight); 5707 } 5708 if ($kde) { 5709 @max_extends = $kde->client_window_region(); 5710 } elsif ($os eq 'win') { 5711 @max_extends = Win32Util::client_window_region($top); 5712 } elsif ($^O eq 'darwin') { 5713 @max_extends = MacOSXUtil::client_window_region($top); 5714 } else { 5715 if ( 5716 # check for broken ->property on 64bit platforms 5717 ($Tk::VERSION >= 804.027501 || $Config{longsize} == 4) && 5718 $top->property("exists", "_NET_CURRENT_DESKTOP", "root") && 5719 $top->property("exists", "_NET_WORKAREA", "root") 5720 ) { 5721 (undef, my $desktop) = $top->property("get", "_NET_CURRENT_DESKTOP", "root"); 5722 if (defined $desktop) { 5723 my @vals = ($top->property("get", "_NET_WORKAREA", "root"))[$desktop*4+1 .. $desktop*4+4]; 5724 if (@vals && defined $vals[0]) { 5725 @max_extends = @vals; 5726 } 5727 } 5728 #$max_extends[2]-=10; # XXX hmmm, does not need to be necessary on gnome/metacity 5729 #$max_extends[3]-=24; # XXX " 5730 } 5731 } 5732 if (!@max_extends) { 5733 # XXX guess width/height of wm borders and title bar 5734 @max_extends = (0, 0, $top->screenwidth-10, $top->screenheight-24); 5735 } 5736 5737 crop_geometry(\@want_extends, \@max_extends); 5738} 5739 5740 5741# after geometry processing 5742sub geometry_dependent_settings { 5743 my $win_width = @want_extends ? $want_extends[GEOMETRY_WIDTH] : $top->width; 5744 my $win_height = @want_extends ? $want_extends[GEOMETRY_HEIGHT] : $top->height; 5745 if ($win_width <= 320 || $win_height <= 320 || $is_handheld) { 5746 $small_icons = 1; 5747 $standard_menubar = 0; 5748 set_canvas_scale(DEFAULT_SMALL_SCALE); 5749 } 5750 if ($is_handheld) { 5751 $use_balloon = 0; 5752 $use_c_balloon = 0; 5753 $use_contexthelp = 0; 5754 $right_is_popup = 0; 5755 $followmouse = 0; 5756 $b2_mode = B2M_NONE; 5757 } 5758} 5759 5760sub define_item_attribs { 5761# grey99 wird als Wei�-Ersatz verwendet (damit die Postscript-Umwandlung 5762# besser funktioniert) 5763# grey98 ebenfalls, aber wenn Outlines eingeschaltet sind, dann wird 5764# diese Farbe nach Wei� umgewandelt. 5765# white wird �berall dort verwendet, wo eine andere Hintergrundfarbe an der 5766# Stelle definiert ist, z.B. beim U-Bahn-Symbol oder in der Legende 5767 my @area_cats = qw(P W I Ae ex-Ae Forest Cemetery Orchard Green Sport Industrial Mine); 5768 %category_color = 5769 ('NN' => '#bdffbd', 5770 'N' => 'grey98', 5771 'NH' => '#ffffb0', # noch blasseres gelb --- XXX �berhaupt unterscheidbar? 5772 'H' => '#ffff90', # blassgelb 5773 'HH' => '#fff800', # kr�ftiges gelb 5774 'BAB' => 'DarkBlue', 5775 'B' => 'red3', 5776 # zweiter (pragmatischer) Versuch einer Qualit�tskategorisierung 5777 # sehr guter Asphalt = guter Asphalt (genauere Kategorisierung nicht 5778 # erforderlich) 5779 # sehr gutes Kopfsteinpflaster = guter Asphalt Q0 5780 # gutes Kopfsteinpflaster = m��iger Asphalt Q1 5781 # m��iges Kopfsteinpflaster = schlechter Asphalt Q2 5782 # schlechtes Kopfsteinpflaster Q3 5783 'Q0' => 'DarkSeaGreen4', 5784 'Q1' => 'YellowGreen', 5785 'Q2' => 'gold', 5786 'Q3' => 'red', 5787 # sonstige Beeintr�chtigungen, die nicht auf schlechte Qualit�t zur�ckzuf�hren 5788 # sind und nur die Geschwindigkeit reduzieren. Geschwindigkeitsreduktion 5789 # wie bei Q. 5790 'q0' => 'DarkSeaGreen4', 5791 'q1' => 'YellowGreen', 5792 'q2' => 'gold', 5793 'q3' => 'red', 5794 'q4' => '#c00000', 5795 # sonstiges 5796 'S' => 'green3', # S-Bahn 5797 'SA' => 'green3', # S-Bahn, Zone A 5798 'SB' => 'green3', # S-Bahn, Zone B 5799 'SC' => '#008000', # S-Bahn, Zone C 5800 'S0' => '#a0b0a0', # stillgelegte S-Bahn 5801 'SBau' => '#a0b0a0', # S-Bahn in Bau 5802 'SBetrieb' => 'green3', # S-Bahn, Betriebsfahrten 5803 ## neues Farbschema an DB-Farben orientiert 5804 ## nicht gut, da nicht gut von Bundesstra�en unterscheidbar 5805 # 'RA' => '#bb171d', # R-Bahn, Zone A 5806 # 'RB' => '#bb171d', # R-Bahn, Zone B 5807 # 'RC' => '#bb171d', # R-Bahn, Zone C 5808 # 'R' => '#bb171d', # R-Bahn, au�erhalb 5809 # 'R0' => '#d0c0c0', # stillgelegte R-Bahn bzw. in Bau 5810 ## altes Farbschema 5811 'RA' => 'green3', # R-Bahn, Zone A 5812 'RB' => 'green3', # R-Bahn, Zone B 5813 'RC' => '#008000', # R-Bahn, Zone C 5814 'R' => '#006400', # R-Bahn, au�erhalb 5815 'R0' => '#a0b0a0', # stillgelegte R-Bahn 5816 'RBau' => '#a0b0a0', # in Bau 5817 'RG' => '#a0c8a0', # G�terbahnen 5818 'RP' => '#49c043', # Parkbahnen... 5819 'U' => '#000080', # U-Bahn 5820 'UA' => '#000080', # U-Bahn, Zone A 5821 'UB' => '#000080', # U-Bahn, Zone B 5822 'U0' => '#a0a0b0', # stillgelegte U-Bahn 5823 'UBau' => '#a0a0b0', # U-Bahn in Bau 5824 'UBetrieb' => '#000080', # U-Bahn, Betriebsfahrten 5825 'W' => '#bad5f7', # Gew�sser 5826 'WR' => '#404080', # Wasserrouten 5827 'P' => '#76c48b', # Parks 5828 'Forest' => '#66b47b', # W�lder 5829 'Cemetery' => '#70c085', # Friedh�fe 5830 'Green' => '#76c48b', # sonstige Gr�nanlagen 5831 'Orchard' => '#e8f8c8', # Kleing�rten (was #80ca94) 5832 'Sport' => '#c8d898', # Sportanlagen (was #86d49b) 5833 'Industrial' => '#d7b8c8', # Industriegebiete 5834 'Ae' => 'white', # Flugh�fen 5835 'ex-Ae' => 'white', # ehemalige Flugh�fen 5836 'Mine' => 'white', # Tagebau, Bergbau 5837 'F' => 'grey99', # sonstige Fl�chen 5838 'SW' => 'red', # Sehensw�rdigkeit 5839 'Shop' => 'red', # Einkaufszentrum, Markthalle 5840 'Q' => 'grey99', # F�hre 5841 'I' => 'grey85', # Inseln (wird sp�ter �berschrieben) 5842 'Z' => 'black', # PLZ-Grenzen 5843 5844 'RW1' => 'SlateBlue', # siehe Radwege.pm 5845 'RW2' => '#00008b', # DarkBlue ist in der Win-Version undefiniert 5846 'RW3' => '#80e599', # fr�her LightBlue, jetzt fast green, da fast kein Unterschied zwischen Suggestiv-/Radstreifen 5847 'RW4' => 'green', 5848 'RW5' => 'orange', 5849 'RW6' => 'yellow3', 5850 'RW7' => 'green', 5851 'RW8' => '#000060', 5852 'RW9' => 'SlateBlue', 5853 'RW10' => 'green', 5854 'RW' => 'SlateBlue', 5855 5856 'sperre0' => 'red', # Tragen 5857 'sperre1' => 'blue', # Einbahnstra�en 5858 'sperre1s' => '#b0b0ff', # Einbahnstra�en (nur mit "einbahn-strict") 5859 'sperre2' => 'red', # voll gesperrt 5860 'sperre3' => 'red', # Wegf�hrung gesperrt 5861 5862 'IN' => 'violet', # Industrieanlagen 5863 'HB' => 'DarkViolet', # Hafenanlagen 5864 'BU' => '#c08080', # Built-up areas 5865 'FO' => '#46b47b', # W�lder 5866 'MO' => '#008080', # Moor 5867 5868 '?' => '#9f0000', 5869 '??' => '#8b0000', # DarkRed, bei Win undefiniert 5870 '?p' => '#af0000', 5871 'GPS' => 'red', # GPS Relation 5872 'GPSs' => "#c000c0", # GPS street 5873 'GPSs~' => "#f4c0f4", # inaccurate 5874 'GPSs~~' => "#e4c8e4", # even more inaccurate 5875 'GPSs?' => "#303030", # unsure 5876 'GPSp' => "#0000a0", # GPS point 5877 'GPSp~' => "#c0c0b0", # GPS point 5878 'GPSp~~' => "#c8c8c0", # GPS point 5879 'GPSp?' => "#303030", # unsure 5880 5881 'CP' => '#a000a0', 5882 'CP2'=> '#a000a0', 5883 'CS' => '#a000a0', 5884 'St' => '#b00080', 5885 'Gf' => '#c00080', 5886 'PI' => '#a000a0', 5887 'P0' => '#a000a0', 5888 5889 '-2' => '#008000', # (relativ) verkehrsarme Stra�e 5890 '-1' => '#00c000', 5891 '+1' => '#c00000', 5892 '+2' => '#800000', # (relativ) verkehrsreiche Stra�e 5893 5894 'green1' => '#7fbb7f', 5895 'green2' => '#008b00', 5896 5897 'radroute' => 'SlateBlue', 5898 5899 'X' => "red", # fallback color 5900 ); 5901 for (qw(Q0 Q1 Q2 Q3 q0 q1 q2 q3 q4)) { # same colors for tendencies 5902 $category_color{$_."-"} = $category_color{$_}; 5903 $category_color{$_."+"} = $category_color{$_}; 5904 } 5905 for (1 .. 10) { 5906 $category_color{"RW".$_."?"} = $category_color{"RW".$_}; 5907 } 5908 $layer_category_color{'e'}->{'CS'} = $category_color{'Q'}; 5909 %category_font_color = 5910 ( 5911 'W' => '#2a45b7', 5912 'U' => '#000060', 5913 'S' => '#006000', 5914 'R' => '#006000', # altes Farbschema 5915 # 'R' => '#a00000',# neues Farbschema 5916 ); 5917 for (qw(UA UB U0)) { $category_font_color{$_} = $category_font_color{"U"} } 5918 for (qw(SA SB SC S0)) { $category_font_color{$_} = $category_font_color{"S"} } 5919 for (qw(RA RB RC R0 RBau RG RP)) { $category_font_color{$_} = $category_font_color{"R"} } 5920 %category_font = 5921 ( 5922 'W' => ($has_xft ? "$sans_serif_font_family:size=%d:matrix=1 -0.15 0 1" : "$sans_serif_font_family %d italic"), 5923 'I' => "$sans_serif_font_family %d italic", 5924 'P' => "$sans_serif_font_family %d", 5925 'Ae' => "$sans_serif_font_family %d", 5926 'ex-Ae' => "$sans_serif_font_family %d", 5927 ); 5928 # all other area categories: 5929 for my $cat (@area_cats) { 5930 if (!exists $category_font{$cat}) { 5931 $category_font{$cat} = $category_font{'P'}; 5932 } 5933 } 5934 # 'above' categories share the same attributes like the non-'above' ones: 5935 for my $cat (@area_cats) { 5936 my $cat_above = $cat . 'above'; 5937 if (!exists $category_color{$cat_above} && exists $category_color{$cat}) { 5938 $category_color{$cat_above} = $category_color{$cat}; 5939 } 5940 if (!exists $category_font{$cat_above} && exists $category_font{$cat}) { 5941 $category_font{$cat_above} = $category_font{$cat}; 5942 } 5943 } 5944 5945 #$pp_color = '#008000'; # bad contrast with rbahn, not good with Bundesstra�e, but better with fragezeichen 5946 # second element is color for real crossing, but not yet activated 5947 #$pp_color = ['#800000', 'blue']; 5948 #$pp_color = '#800000'; # bad contrast with fragezeichen 5949 $pp_color = '#000080'; 5950 5951 for my $nr (0, 1, 2) { 5952 $category_color{'W' . $nr} = $category_color{'W'}; 5953 $category_font_color{'W' . $nr} = $category_font_color{'W'}; 5954 $category_font{'W' . $nr} = $category_font{'W'}; 5955 } 5956 # fallback, falls kein %category_color definiert ist 5957 %str_color = 5958 ('s' => 'yellow', 5959 'L' => 'red', 5960 'qs' => 'red', 5961 'ql' => 'red', 5962 'hs' => 'red', 5963 'hl' => 'red', 5964 'nl' => 'black', 5965 'gr' => 'green', 5966 ); 5967 %p_color = 5968 (); 5969 5970 # XXX use klein and klein2 versions, how? array/hash for different scalings? 5971 %category_image = 5972 ('bg' => "aufzug.gif", # bg=behindertengerecht 5973 'bf' => "rampe.gif", # bf=behindertenfreundlich 5974 ); 5975 5976 %category_stipple = 5977 ( 5978 'Cemetery' => 'crosses.xbm', 5979 'Cemetery|religion:jewish' => 'stars_of_david.xbm', 5980 'Cemetery|religion:muslim' => 'halfmoons.xbm', 5981 ); 5982 5983 %line_width = 5984 ('s-NN' => [1, 1, 2, 2, 4, 7], 5985 's-N' => [1, 1, 2, 2, 4, 7], 5986 's-NH' => [1, 1, 2, 3, 5, 8], 5987 's-H' => [1, 2, 3, 4, 6, 10], 5988 's-HH' => [1, 2, 3, 4, 6, 10], 5989 's-B' => [1, 2, 3, 4, 6, 10], 5990 's-BAB' => [1, 2, 3, 4, 6, 10], 5991 'sBAB-BAB' => [1, 2, 3, 4, 6, 10], 5992 'comm' => [1, 2, 3, 4, 6, 10], 5993 'mount' => [1, 2, 3, 4, 6, 10], 5994 'qs' => [3, 4, 5, 6, 8, 12], 5995 'hs' => [3, 4, 5, 6, 8, 12], 5996 'temp_sperre_s' => [5, 6, 7, 8, 10, 14], 5997 'rw' => [1, 2, 3, 4, 6, 10], 5998 'l' => [2, 2, 3, 4, 6, 10], 5999 'gr' => [5, 7, 8, 9, 10, 14], # s-H + 4 pixels 6000 'ql' => [3, 4, 5, 6, 8, 12], 6001 'hl' => [3, 4, 5, 6, 8, 12], 6002 'z' => [1, 1, 2, 3, 5, 8], 6003 'g' => [1, 2, 3, 4, 6, 10], 6004 'e' => [1, 2, 3, 4, 6, 10], 6005 # 'sperre0' => [3, 5, 7, 9, 11,15], 6006 'sperre0' => [1, 2, 2, 2, 3, 3], 6007 'sperre1' => [0, 0, 2, 3, 4, 6], 6008 'sperre2' => [0, 0, 2, 3, 5, 8], 6009 'sperre3' => [0, 0, 1, 2, 4, 6], 6010 'sperre3nocross' => [0, 0, 1, 1, 2, 3], 6011 'w' => [1, 1, 2, 2, 4, 7], 6012 'w-W0' => [0, 1, 1, 1, 3, 5], 6013 'w-W1' => [2, 2, 3, 5, 7, 11], 6014 'w-W2' => [3, 4, 6, 8, 10,13], 6015 'comm-scenic-View' => [4, 7, 9, 12, 16, 20], 6016 'u-UBetrieb' => [1, 1, 2, 3, 4, 6], 6017 'b-SBetrieb' => [1, 1, 2, 3, 4, 6], 6018 'default' => [1, 2, 3, 4, 6, 10], 6019 ); 6020 foreach (qw/NN N NH H HH B BAB/) { 6021 $line_width{"l-$_"} = [@{ $line_width{"s-$_"}}]; 6022 } 6023 foreach (qw/sperre1s/) { 6024 $line_width{$_} = [@{ $line_width{"sperre1"}}]; 6025 } 6026 foreach (qw/gBO gP gD/) { 6027 $line_width{$_} = [@{ $line_width{"g"}}]; 6028 } 6029 my %narrow_comments_types = map {($_,1)} qw(tram misc mount kfzverkehr scenic); 6030 foreach (@comments_types) { 6031 if ($narrow_comments_types{$_}) { 6032 $line_width{'comm-'.$_} = [1, 1, 1, 1, 2, 3]; 6033 } else { 6034 $line_width{"comm-".$_} = [@{ $line_width{"comm"}}]; 6035 } 6036 } 6037 6038 %line_dash = 6039 ('qs' => [5,2], 6040 'ql' => [5,2], 6041 'hs' => [2,5], 6042 'hl' => [2,5], 6043 'temp_sperre_s' => [2,5], 6044 'nl' => [2,4], 6045 'comm' => [5,2], 6046 'comm-tram' => [2,6], 6047 'mount'=> [5,2], 6048 'e' => [5,2], # F�hren 6049 'g' => [8,5,2,5], # Grenzen 6050 'z' => [8,5,2,5], # PLZ-Grenzen 6051 'sperre3' => [6,2], 6052 'fz' => [8,5], 6053 'Tu' => [4,5], # Tunnel (addinfo) 6054 ); 6055 %category_dash = 6056 ('R0' => [1,5], 6057 'U0' => [1,5], 6058 'S0' => [1,5], 6059 'radroute' => [1,15], 6060 ); 6061 %category_capstyle = 6062 ('radroute' => 'round'); # XXX $capstyle_round not available at this time! 6063 foreach (qw/gBO gP gD/) { 6064 $line_dash{$_} = [@{ $line_dash{"g"}}]; 6065 } 6066 foreach (grep { $_ !~ m{^(tram|ferry|cyclepath)$} } @comments_types) { 6067 $line_dash{"comm-".$_} = [@{ $line_dash{"comm"}}]; 6068 } 6069 $line_dash{'comm-ferry'} = $line_dash{'e'}; 6070 6071 %line_length = 6072 ('sperre1' => [0, 0, 4, 5, 7, 10], 6073 'sperre2' => [0, 0, 3, 4, 6, 8], 6074 'default' => [2, 3, 4, 5, 7, 10], 6075 ); 6076 foreach (qw/sperre1s/) { 6077 $line_length{$_} = [@{ $line_length{"sperre1"}}]; 6078 } 6079 6080 %category_line_arrow = 6081 ('PI' => 'last', 6082 'P0' => 'last', 6083 ); 6084 %category_line_shorten = 6085 ('CP' => 1, 6086 'P0' => 1, 6087 ); 6088 %category_line_shorten_end = 6089 ('CP2' => 1, 6090 'PI' => 1, 6091 ); 6092 # Label size per category 6093 %category_size = 6094 ('NN' => 7, 6095 'N' => 8, 6096 'NH' => 9, 6097 'H' => 10, 6098 'HH' => 10, 6099 'B' => 10, 6100 'BAB'=> 10, 6101 'W' => 12); 6102 %category_point_size = 6103 ('?' => 10, 6104 ); 6105 %outline_color = 6106 ('s' => 'grey70', 6107 'l' => 'grey70', 6108 'w' => 'blue4', 6109 'i' => 'blue4', 6110 ); 6111 %str_file = 6112 (# "primary" 6113 's' => 'strassen', 6114 'l' => 'landstrassen', # this is really scoped 6115 'u' => 'ubahn', 6116 'b' => 'sbahn', 6117 'r' => 'rbahn', 6118 'w' => 'wasserstrassen', # this is really scoped 6119 'f' => 'flaechen', 6120 'v' => 'sehenswuerdigkeit', 6121 'z' => 'plz', 6122 'g' => 'berlin', 6123 'gP' => "potsdam", 6124 'gD' => "deutschland", 6125 'gBO'=> "berlin_ortsteile", 6126 'e' => 'faehren', 6127 # dependent 6128 'rw' => 'radwege', 6129 'qs' => 'qualitaet_s', 6130 'ql' => 'qualitaet_l', 6131 'hs' => 'handicap_s', 6132 'hl' => 'handicap_l', 6133 'nl' => 'nolighting', 6134 'gr' => 'green', 6135 'comm' => 'comments', # this is splitted into multiple files 6136 'mount' => 'mount', 6137 # special 6138 'fz' => "fragezeichen", 6139 'wr' => "wasserrouten", 6140 ); 6141 foreach my $type (@comments_types) { 6142 $str_file{"comm-$type"} = "comments_$type"; 6143 } 6144 if ($devel_host) { 6145 $str_file{"is"} = "$FindBin::RealBin/projects/infrasystem/data/landstrassen-corrected"; 6146 } 6147 %p_file = 6148 ('lsa' => 'ampeln', 6149 'u' => 'ubahnhof', 6150 'u_bg' => 'ubahnhof_bg', 6151 'b' => 'sbahnhof', 6152 'b_bg' => 'sbahnhof_bg', 6153 'r' => 'rbahnhof', 6154 'o' => 'orte', # XXX scoped 6155 'sperre' => $sperre_file, 6156 'sperre_u' => 'gesperrt_u', 6157 'sperre_b' => 'gesperrt_s', 6158 'sperre_r' => 'gesperrt_r', 6159 'obst' => 'obst', 6160 'pl' => 'plaetze', 6161 'vf' => 'vorfahrt', 6162 6163 'kn' => 'kneipen', 6164 'ki' => 'kinos', 6165 'rest' => 'restaurants', 6166 'GU' => 'grenzuebergaenge', 6167 ); 6168 6169 # Feld-Elemente 6170 # 0: Bezeichnung, Singular 6171 # 1: Bezeichnung, Plural 6172 # 2: Linien (bool) 6173 # 3: (falls vorhanden) lange Bezeichnung 6174 %str_attrib = 6175 ('s' => [M"Stra�e", M"Stra�en", 0], 6176 'l' => [M"Landstra�e", M"Landstra�en", 0], 6177 'u' => [M"U-Bahnlinie", M"U-Bahnlinien", 1], 6178 'b' => [M"S-Bahnlinie", M"S-Bahnlinien", 1], 6179 'r' => [M"R-Bahnlinie", M"R-Bahnlinien", 1], 6180 'w' => [M"Gew�sser", M"Gew�sser", 0], 6181 'f' => [M"Fl�che", M"Fl�chen", 0], 6182 'v' => [M"Sehensw�rdigkeit", M"Sehensw�rdigkeiten", 0], 6183 'z' => [M"PLZ-Gebiet", M"PLZ-Gebiete", 0], 6184 'g' => [M"Grenze von Berlin", M"Grenze von Berlin", 0], # see below for override 6185 'gP' => [M"Grenze von Potsdam", M"Grenze von Potsdam", 0], 6186 'gD' => [M"Staatsgrenze", M"Staatsgrenze", 0], 6187 'gBO' => [M"Berliner Ortsteil", M"Berliner Ortsteile", 0], # see below for override 6188 'e' => [M"F�hre", M"F�hren", 0], 6189 'rw' => [M"Radweg", M"Radwege", 0], 6190 'qs' => [M"Stra�enqualit�t", M"Stra�enqualit�t", 0], 6191 'ql' => [M"Stra�enqualit�t (Landstra�e)", M"Stra�enqualit�t (Landstra�e)", 0], 6192 'hs' => [M"Sonst. Beeintr�chtigungen", M"Sonst. Beeintr�chtigungen", 0], 6193 'hl' => [M"Sonst. Beeintr�chtigungen (Landstra�e)", M"Sonst. Beeintr�chtigungen (Landstra�e)", 0], 6194 'nl' => [M"Unbeleuchtete Stra�e", M"Unbeleuchtete Stra�en", 0], 6195 'gr' => [M"Gr�ner Weg", M"Gr�ne Wege", 0], 6196 'comm' => [M"Kommentare", M"Kommentare", 0], 6197 # XXX specific comm types? 6198 'mount' => [M"Steigung", M"Steigungen", 0], 6199 'wr' => [M"Wasserroute", M"Wasserrouten", undef], 6200 'fz' => [M"Unbekannte Stra�e", M"Unbekannte Stra�en", 1], 6201 ); 6202 if (!defined $city || $city ne 'Berlin') { 6203 $str_attrib{g} = [M"Ortsgrenze", M"Ortsgrenzen", 0]; 6204 $str_attrib{gBO} = [M"Ortsteilgrenze", M"Ortsteilgrenzen", 0]; 6205 } 6206 %p_attrib = 6207 ('lsa' => [M"Ampel", M"Ampeln", undef], 6208 'u' => [M"U-Bahnhof", M"U-Bahnh�fe", undef], 6209 'u_bg' => [M"Fahrradfreundlicher Zugang (U-Bahn)", M"Fahrradfreundliche Zug�nge (U-Bahn)", undef], 6210 'b' => [M"S-Bahnhof", M"S-Bahnh�fe", undef], 6211 'u_bg' => [M"Fahrradfreundlicher Zugang (S-Bahn)", M"Fahrradfreundliche Zug�nge (S-Bahn)", undef], 6212 'r' => [M"R-Bahnhof", M"R-Bahnh�fe", undef], 6213 'r_bg' => [M"Fahrradfreundlicher Zugang (Regionalbahn)", M"Fahrradfreundliche Zug�nge (Regionalbahn)", undef], 6214 'o' => [M"Ort", M"Orte", undef], 6215 'p' => [M"Haltestelle", M"Haltestellen", undef], 6216 'obst' => [M"Obst", M"Obst", undef], 6217 'pl' => [M"Platz/Br�cke",M"Pl�tze/Br�cken",undef], 6218 'vf' => [M"Vorfahrt", M"Vorfahrt", undef], 6219 'pp' => [M"Kreuzung", M"Kreuzungen", undef], 6220 'kn' => [M"Kneipe", M"Kneipen", undef], 6221 'ki' => [M"Kino", M"Kinos", undef], 6222 'rest' => [M"Restaurant", M"Restaurants", undef], 6223 'hoehe' => [M"H�henangabe", M"H�henangaben", undef], 6224 'personal' => [M"Pers�nlicher Ort", M"Pers�nliche Orte", undef], 6225 'GU' => [M"Grenz�bergang", M"Grenz�berg�nge", undef], 6226 ); 6227 %category_attrib = 6228 ('UA' => [M"U-Bahn Zone A", undef, undef], 6229 'UB' => [M"U-Bahn Zone B", undef, undef], 6230 'U0' => [M"stillgelegte U-Bahn", undef, undef], 6231 'UBau' => [M"U-Bahn in Bau", undef, undef], 6232 'UBetrieb' => [M"U-Bahn, nur Betriebsfahrten", undef, undef], 6233 'SA' => [M"S-Bahn Zone A", undef, undef], 6234 'SB' => [M"S-Bahn Zone B", undef, undef], 6235 'SC' => [M"S-Bahn Zone C", undef, undef], 6236 'S0' => [M"stillgelegte S-Bahn", undef, undef], 6237 'SBau' => [M"S-Bahn in Bau", undef, undef], 6238 'SBetrieb' => [M"S-Bahn, nur Betriebsfahrten", undef, undef], 6239 'RA' => [M"R-Bahn Zone A", undef, undef], 6240 'RB' => [M"R-Bahn Zone B", undef, undef], 6241 'RC' => [M"R-Bahn Zone C", undef, undef], 6242 'R' => [M"R-Bahn au�erhalb Berlin ABC", undef, undef], 6243 'R0' => [M"stillgelegte Bahnstrecke", M"stillgelegte Bahnstrecken", undef], 6244 'RBau' => [M"Bahnstrecke in Bau", M"Bahnstrecken in Bau", undef], 6245 'RG' => [M"G�terbahn/Verbindungsstrecke", M"G�terbahnen/Verbindungsstrecken", undef], 6246 'RP' => [M"Park-/Kleinbahn", M"Park-/Kleinbahnen", undef], 6247 'HH' => [M"wichtige Hauptstra�e", M"wichtige Hauptstra�en", undef], 6248 'B' => [M"Bundesstra�e", M"Bundesstra�en", undef], 6249 'H' => [M"Hauptstra�e", M"Hauptstra�en", undef], 6250 'N' => [M"Nebenstra�e", M"Nebenstra�en", undef], 6251 'NH' => [M"wichtige Nebenstra�e", M"wichtige Nebenstra�en", undef], 6252 'NN' => [M"f�r Kfz gesperrte Stra�e", M"f�r Kfz gesperrte Stra�en", undef], 6253 'Pl' => [M"Platz", M"Pl�tze", undef], 6254 'BAB'=> [M"Autobahn", M"Autobahnen", undef], 6255 'P' => [M"Park", M"Parks", undef], 6256 'Forest' => [M"Wald", M"W�lder", undef], 6257 'Cemetery' => [M"Friedhof", M"Friedh�fe", undef], 6258 'Green' => [M"Gr�nanlage", M"Gr�nanlagen", undef], 6259 'Orchard' => [M"Kleing�rten", M"Kleing�rten", undef], 6260 'Sport' => [M"Sportanlage", M"Sportanlagen", undef], 6261 'Industrial' => [M"Industriegebiet", M"Industriegebiete", undef], 6262 'Mine' => [M"Tagebau", undef, undef], 6263 'Ae' => [M"Flughafen", M"Flugh�fen", undef], 6264 'ex-Ae' => [M"ehemaliger Flughafen", M"ehemalige Flugh�fen", undef], 6265 'Q0' => [M"sehr guter Belag", undef, undef, 6266 M"sehr guter Belag (Asphalt)"], 6267 'Q1' => [M"guter Belag", undef, undef, 6268 M"guter Belag (Asphalt oder gutes Kopfsteinpflaster)"], 6269 'Q2' => [M"m��iger Belag", undef, undef, 6270 M"m��iger Belag (schlechter Asphalt oder m��iges Kopfsteinpflaster)"], 6271 'Q3' => [M"schlechter Belag", undef, undef, 6272 M"schlechter Belag (Katzenkopfsteinpflaster oder unbefestigte Wege)"], 6273 'q0' => [M"keine", undef, undef, 6274 M"keine Beeintr�chtigungen"], 6275 'q1' => [M"auf ca. 25 km/h", undef, undef, 6276 M"Beeintr�chtigungen auf ca. 25 km/h"], 6277 'q2' => [M"auf ca. 18 km/h", undef, undef, 6278 M"Beeintr�chtigungen auf ca. 18 km/h"], 6279 'q3' => [M"auf ca. 13 km/h", undef, undef, 6280 M"Beeintr�chtigungen auf ca. 13 km/h"], 6281 'q4' => [M"auf Schrittgeschwidigkeit", undef, undef, 6282 M"Beeintr�chtigungen auf Schrittgeschwindigkeit"], 6283 6284 '6' => [M"Gro�- oder Millionenstadt", M"Gro�- oder Millionenst�dte", undef], 6285 '5' => [M"Gro�stadt", M"Gro�st�dte", undef], 6286 '4' => [M"Ortskategorie 4", M"Ortskategorie 4", undef], 6287 '3' => [M"Ortskategorie 3", M"Ortskategorie 3", undef], 6288 '2' => [M"Ortskategorie 2", M"Ortskategorie 2", undef], 6289 '1' => [M"kleiner Ort", M"kleine Orte", undef], 6290 '0' => [M"Ortsteil", M"Ortsteile", undef], 6291 'Zbr'=> [M"Zugbr�cke", M"Zugbr�cken", undef], 6292 'Br' => [M"Br�cke", M"Br�cken", undef], 6293 'Tu' => [M"Tunnel", M"Tunnel", undef], 6294 'CS' => [M"streckenbezogener Kommentar", M"streckenbezogene Kommentare", undef], 6295 'CP' => [M"punktbezogener Kommentar (A-B-C)", M"punktbezogene Kommentare (A-B-C)", undef], 6296 'CP2'=> [M"punktbezogener Kommentar (A-B)", M"punktbezogene Kommentare (A-B)", undef], 6297 'PI' => [M"genaue Wegbeschreibung", undef, undef], 6298 '-2' => [M"relativ sehr ruhiger Kfz-Verkehr", undef, undef], 6299 '-1' => [M"relativ ruhiger Kfz-Verkehr", undef, undef], 6300 '+1' => [M"relativ starker Kfz-Verkehr", undef, undef], 6301 '+2' => [M"relativ sehr starker Kfz-Verkehr", undef, undef], 6302 'St' => [M"Steigung", M"Steigungen", undef], 6303 'Gf' => [M"Gef�lle", M"Gef�lle", undef], 6304 'Z' => [M"Grenze", M"Grenzen", undef], 6305 'Q' => [M"F�hre", M"F�hren", undef], 6306 'green1' => [M"gr�ner Weg", M"gr�ne Wege", undef], 6307 'green2' => [M"besonders gr�ner Weg", M"besonders gr�ne Wege", undef], 6308 'HNR'=> [M"Hausnummer", M"Hausnummern", undef], 6309 'NL' => [M"unbeleuchtete Stra�e", M"unbeleuchtete Stra�en", undef], 6310 'SW' => [M"Sehensw�rdigkeit", M"Sehensw�rdigkeiten", undef], 6311 'I' => [M"Insel", M"Inseln", undef], 6312 'W' => [M"Gew�sser, nicht kategorisiert", undef, undef], 6313 'W0' => [M"unwichtiges Gew�sser", undef, undef], 6314 'W1' => [M"Gew�sser", undef, undef], 6315 'W2' => [M"gr��eres Gew�sser", undef, undef], 6316 'WR' => [M"Wasserroute", M"Wasserrouten", undef], 6317 'radroute' => [M"Radroute", M"Radrouten", undef], 6318 ); 6319 foreach my $cat (@area_cats) { 6320 my $cat_above = $cat . 'above'; 6321 if (exists $category_attrib{$cat} && !exists $category_attrib{$cat_above}) { 6322 $category_attrib{$cat_above} = $category_attrib{$cat}; 6323 } 6324 } 6325 foreach (@Radwege::category_order) { 6326 if (defined $Radwege::category_code{$_}) { 6327 $category_attrib{$Radwege::category_code{$_}} = 6328 [$Radwege::category_name{$_}, $Radwege::category_plural{$_}, undef]; 6329 } 6330 } 6331 6332 %obst_file = 6333 ('apfel' => 'apfel', 6334 'kirsche' => 'kirsche', 6335 'birne' => 'birne', 6336 'pflaume' => 'pflaume', 6337 ); 6338 6339 # f�r Orte und Sonstiges 6340 $xadd_anchor_type->{'o'} = {'w' => 4, 'n' => 0, 'e' => -4, 's' => 0, 6341 'nw' => 2, 'sw' => 2}; 6342 $yadd_anchor_type->{'o'} = {'w' => 0, 'n' => 1, 'e' => 0, 's' => -1, 6343 'nw' => 1, 'sw' => -1}; 6344 $label_spaceadd{'o'} = " "; 6345 6346 # f�r Routen 6347 $xadd_anchor_type->{'route'} = {'w' => 10, 'n' => 0, 'e' => -10, 's' => 0, 6348 'nw' => 5, 'sw' => 5}; 6349 $yadd_anchor_type->{'route'} = {'w' => 0, 'n' => 10, 'e' => 0, 's' => -10, 6350 'nw' => 5, 'sw' => -5}; 6351 # $label_spaceadd not needed here 6352 6353 # U-Bahnsymbole (auch S-Bahn, R-Bahn etc.) 6354 # XXX This should be variable depending on the drawn icon (normal, klein, mini) 6355 $xadd_anchor_type->{'u'} = {'w' => 9, 'n' => 0, 'e' => -9, 's' => 0, 6356 'nw' => 5, 'sw' => 5}; 6357 $yadd_anchor_type->{'u'} = {'w' => 0, 'n' => 9, 'e' => 0, 's' => -9, 6358 'nw' => 5, 'sw' => -5}; 6359 $label_spaceadd{'u'} = " "; 6360 6361 # Sehensw�rdigkeiten (star) 6362 $xadd_anchor_type->{'v'} = {'w' => 8, 'n' => 0, 'e' => -8, 's' => 0, 6363 'nw' => 5, 'sw' => 5}; 6364 $yadd_anchor_type->{'v'} = {'w' => 0, 'n' => 8, 'e' => 0, 's' => -8, 6365 'nw' => 5, 'sw' => -5}; 6366 $label_spaceadd{'v'} = " "; 6367 6368 %tag_group = # group related tags (for stacking) 6369 ('str_s' => ['s-out', 'gr', 'rw', 6370 's-NN', 's-N', 's-NH', 's-H', 's-HH', 's-B', 's-BAB', 'sBAB-BAB', 'sBAB-fg', 6371 'comm', (map { "comm-$_" } @comments_types), 6372 'nl', 'qs', 'hs', 'mount', 6373 's-label-bg', 'sBAB-label-bg', 's-label', 'sBAB-label', 6374 'hoehe', 'vf-bg', 6375 'sperre', 'temp_sperre_s', 'temp_sperre', 6376 'delnet', 'pl-fg', 'lsa-bg', 'vf-fg', 'lsa-fg'], 6377 'str_l' => ['l-out', 'l', 'comm', 6378 (map { "comm-$_" } @comments_types), 6379 'ql', 'hl', 'l-label-bg', 'l-label'], # XXX mount? 6380 'p_o' => ['o', 'O'], 6381 'p_p' => ['p'], 6382 'str_u' => ['u', 'sperre_u', 'u-bg', 'u-fg', 'u_bg-img', 'u-label'], 6383 'str_b' => ['b', 'sperre_b', 'b-bg', 'b-fg', 'b_bg-img', 'b-label'], 6384 'str_r' => ['r', 'sperre_r', 'r-bg', 'r-fg', 'r_bg-img', 'r-label'], 6385 'str_w' => ['w-out', 'w', 'i-out', 'i', 'w-label-bg', 'w-label', 'i-label-bg', 'i-label'], 6386 'str_f' => ['f', 'f-label-bg', 'f-label', 'f-Pabove'], 6387 'str_g' => ['z', 'g', 'gBO', 'gP', 'gD', 'gBO-label-bg', 'gBO-label', 'GU-img'], 6388 'p_kn' => ['kn', 'kn-bg', 'kn-fg', 'ki', 'ki-bg', 'ki-fg', 'rest', 'rest-bg', 'rest-fg'], 6389 'map' => ['map'], 6390 'route' => ['route'], 6391 'v' => ['v', 'v-fg'], 6392 'e' => ['e', 'e-img'], 6393 ); 6394 6395 # normale Reihenfolge f�r das �bereinanderlegen bei restack() 6396 #XXX labels sollten grunds�tzlich immer oben sein. Problematisch bei tag_groups 6397 # tags in the form '*...*' are special and used just as markers 6398 @normal_stack_order = 6399 (qw(map f w-out w i-out i f-Pabove *landuse* e e-img 6400 gP gD z g gP gD gBO 6401 s-out l-out show gr rw s-NN s-N s-NH s-H s-HH s-B s-BAB sBAB sBAB-BAB sBAB-fg l v 6402 f-label-bg wr w-label-bg gBO-label-bg f-label w-label i-label gBO-label 6403 u sperre_u u-bg u-fg u_bg-img r sperre_r b sperre_b 6404 r-bg r-fg r_bg-img b-bg b-fg b_bg-img GU-img 6405 u-label r-label b-label 6406 hoehe vf-bg sperre temp_sperre_s temp_sperre v-fg obst 6407 fz *route* route gps_track comm), 6408 (map { "comm-$_" } @comments_types), 6409 qw(comm-route-label-bg comm-route-label qs hs ql hl mount nl delnet 6410 crosshairs 6411 O o p pl-fg vf-fg lsas lsa-bg lsa-fg lsas-t 6412 pp kn-bg kn-fg ki-bg ki-fg rest-bg rest-fg 6413 fz-label s-label-bg sBAB-label-bg s-label sBAB-label l-label-bg l-label 6414 personal-fg personal-label ovl 6415 gpsanimrect zoomrect), 6416 ); 6417 %comment_cat_labels = 6418 (ferry => M"Informationen zu F�hren", 6419 misc => M"Sonstige Kommentare", 6420 path => M"Wegf�hrung", 6421 route => M"Radrouten", 6422 tram => M"Tram auf Fahrbahn", 6423 kfzverkehr => M"Kommentare zum Kfz-Verkehr", 6424 scenic => M"Sch�ne Strecken", 6425 danger => M"Gef�hrliche Stellen", 6426 ); 6427} 6428 6429sub generate_plot_functions { 6430 $plotstr_draw_sub = <<'EOF'; 6431 sub { 6432 my $ret = shift; 6433 my $strname = $ret->[Strassen::NAME]; 6434 my @kreuzungen = @{$ret->[Strassen::COORDS]}; 6435 @kreuzungen = map { $conv->($_) } @kreuzungen 6436 if $conv; 6437 my $cat_hin = $ret->[Strassen::CAT]; 6438 my $cat_rueck; 6439 my(@addinfo_hin, @addinfo_rueck); 6440 if ($cat_hin =~ /^(.*);(.*)$/) { 6441 ($cat_hin, $cat_rueck) = ($1, $2); 6442 } 6443 if ($cat_hin =~ /^(.+?)::(.*)$/) { # XXX will change 6444 $cat_hin = $1; 6445 @addinfo_hin = split ':', $2; 6446 } 6447 if (defined $cat_rueck && $cat_rueck =~ /^(.+?)::(.*)$/) { # XXX this will change! 6448 $cat_rueck = $1; 6449 @addinfo_rueck = split ':', $2; 6450 } 6451# XXX Problems with cat = ";anything": $cat_hin is empty and thus always 6452# restricted. Workaround: always use "anything;" with the reversed 6453# coord list. But nevertheless $ignore and $restrict won't work correctly. 6454 return if defined $ignore and $cat_hin =~ /$ignore/; 6455 return if defined $restrict and $cat_hin !~ /$restrict/; 6456 if (!$edit_normal_mode) { # we want to see everything in edit mode 6457 return if first { $_ eq "igndisp" } @addinfo_hin; 6458 } 6459 my $this_color_hin = $cat_hin =~ /^\#/ ? $cat_hin : 6460 ($layer_category_color{$abk} && $layer_category_color{$abk}{$cat_hin}) 6461 || $category_color{$cat_hin} 6462 || $str_color{$abk} || 'white'; 6463 my $this_color_rueck = defined $cat_rueck ? 6464 ($cat_rueck =~ /^\#/ ? $cat_rueck : 6465 ($layer_category_color{$abk} && $layer_category_color{$abk}{$cat_rueck}) 6466 || $category_color{$cat_rueck} 6467 || $str_color{$abk} || 'white') : 6468 'white'; 6469 my $this_width_hin = ($layer_category_line_width{$abk} && $layer_category_line_width{$abk}{$cat_hin}) 6470 || $category_width{$cat_hin} || $default_width || 1; 6471 my $this_width_rueck = defined $cat_rueck ? 6472 (($layer_category_line_width{$abk} && $layer_category_line_width{$abk}{$cat_rueck}) || $category_width{$cat_rueck} || $default_width || 1) : 6473 1; 6474 my @coordlist; 6475 CROSSINGS_LOOP: 6476 foreach (@kreuzungen) { 6477 TRY: { 6478 my($xx, $yy); 6479 if (!$edit_mode && !$edit_mode_flag) { 6480 ($xx, $yy) = split /,/, $_; 6481 if (!defined $yy) { # ignore invalid coords like "*" 6482 next CROSSINGS_LOOP; 6483 } 6484 } elsif ($edit_mode_flag) { 6485 /^(?::.*:)?(-?[\d\.]+),(-?[\d\.]+)$/; 6486 ($xx, $yy) = ($1, $2); 6487 next CROSSINGS_LOOP if !defined $yy; 6488 } elsif ($edit_mode && 6489 /([A-Za-z]+)?(-?[\d\.]+),(-?[\d\.]+)$/) { 6490 # XXX Verwendung von data/BASE (hier und �berall) 6491 my $this_coordsys = (defined $1 ? $1 : ''); 6492 if ($this_coordsys eq $coordsys || 6493 (!($this_coordsys ne '' || $coordsys ne 'B'))) { 6494 ($xx, $yy) = ($2, $3); 6495 } else { 6496 # the hard way: convert it 6497 $this_coordsys = 'B' if $this_coordsys eq ''; 6498 ($xx,$yy) = $Karte::map_by_coordsys{$this_coordsys}->map2map($coord_system_obj, $2, $3); 6499#warn "($xx,$yy)"; 6500 } 6501 } else { 6502 last TRY; 6503 } 6504 push @coordlist, $transpose->($xx, $yy); 6505 if ($p_draw{'pp'} && ($p_sub_draw{"pp-$abk"}||$p_sub_draw{"pp-all"})) { 6506 my($x, $y) = @coordlist[$#coordlist-1 .. $#coordlist]; 6507 my $pp_cross_or_kurve_tag; 6508## This is not correct and therefore not used. 6509## The net should be plain without "gesperrt"/"oneway" bits. 6510# if ($net && $net->{Net}) { 6511# if (scalar(keys(%{$net->{Net}{"$xx,$yy"}})) < 3) { 6512# $pp_cross_or_kurve_tag = "ppkvp"; 6513# } else { 6514# $pp_cross_or_kurve_tag = "ppcrs"; 6515# } 6516# } 6517 # keine Verwendung von _coord_as_string 6518 $c->createLine 6519 ($x, $y, $x, $y, 6520 -tags => ['pp', "$xx,$yy", undef, "pp-$abk", 6521 ($pp_cross_or_kurve_tag ? $pp_cross_or_kurve_tag : ())], 6522 ); 6523 } 6524 } 6525 } 6526 if (@coordlist > 0) { 6527 my $abk = $abk; 6528 my($mx,$my); 6529 my $image; 6530 my $anchor = "c"; 6531 my $category = $cat_hin; # used for undirected things 6532 my $item; # canvas item drawn 6533 6534 my $line_shorten_hin = ($layer_category_line_shorten{$abk} && $layer_category_line_shorten{$abk}{$cat_hin}) || $layer_line_shorten{$abk} || $category_line_shorten{$cat_hin} || $line_shorten{$abk}; 6535 if (defined $line_shorten_hin) { # XXX no $cat_rueck handling 6536 line_shorten(\@coordlist); 6537 } else { 6538 my $line_shorten_end_hin = ($layer_category_line_shorten_end{$abk} && $layer_category_line_shorten_end{$abk}{$cat_hin}) || $layer_line_shorten_end{$abk} || $category_line_shorten_end{$cat_hin} || $line_shorten_end{$abk}; 6539 if (defined $line_shorten_end_hin) { # XXX no $cat_rueck handling 6540 line_shorten_end(\@coordlist); 6541 } 6542 } 6543 6544 if ($layer_category_image{$abk} && defined $layer_category_image{$abk}{$cat_hin}) { 6545 $cat_hin = "IMG:$layer_category_image{$abk}{$cat_hin}"; 6546 } elsif (defined $category_image{$cat_hin}) { 6547 $cat_hin = "IMG:$category_image{$cat_hin}"; 6548 } 6549 6550 my $sight_draw = sub { 6551 # speciality for sights: draw a star 6552 if (!defined $mx) { 6553 if (@coordlist > 2) { 6554 ($mx,$my) = get_polygon_center(@coordlist); 6555 } 6556 if (!defined $mx) { 6557 ($mx,$my) = @coordlist[0,1]; 6558 } 6559 } 6560 if ($image) { 6561 if (!$photo{$image}) { 6562 my $f; 6563 for my $subdir ("images", "data") { 6564 $f = maybe_expand_image_file($image, $str_file{$abk}, $subdir); 6565 if ($f && -r $f) { 6566 $photo{$image} = image_from_file($top, $f); 6567 last; 6568 } 6569 } 6570 if (!$photo{$image}) { 6571 warn "Can't find photo $image (1)"; 6572 } 6573 } 6574 if ($photo{$image}) { 6575 $c->createImage($mx,$my,-image => $photo{$image}, 6576 -anchor => $anchor, 6577 -tags => ["$abk-fg", $strname]); 6578 } else { 6579 warn "No image for $image"; 6580 } 6581 } else { 6582 $c->createImage($mx,$my,-image => $star_photo, 6583 -tags => ["$abk-fg", $strname]); 6584 } 6585 }; 6586 6587 my $draw_strname_for_area = sub { 6588 my($name, $add) = split(/\|/, $strname); 6589 $name = "" if !defined $name; 6590 ## The addition is mostly for missing geographic context; not necessary when drawing 6591 #if ($add) { 6592 # $name .= " $add"; 6593 #} 6594 $name =~ s/\cK/\n/g; # vert tab -> newline 6595 ($mx,$my) = get_polygon_center(@coordlist); 6596 if (!defined $mx || ! do { 6597 my @zipped_coordlist; 6598 for(my $i = 0; $i < $#coordlist; $i+=2) { 6599 push @zipped_coordlist, [$coordlist[$i], $coordlist[$i+1]]; 6600 } 6601 point_in_polygon([$mx,$my], \@zipped_coordlist); 6602 }) { 6603 my $middle = int $#coordlist/2; 6604 if ($middle%2 != 0) { 6605 $middle--; 6606 } 6607 ($mx,$my) = @coordlist[$middle,$middle+1]; 6608 } 6609 6610 my $abk_fg = $abk; 6611 if ($abk eq 'v') { 6612 $abk_fg = 'v-fg'; 6613 } elsif ($abk =~ /^(?:[fw]|gBO)$/) { 6614 $abk_fg = $abk."-label"; 6615 } 6616 my $tags = [$abk_fg, $strname]; 6617 my %args = (-text => $name, 6618 -tags => $tags, 6619 -outlinewidth => 2, 6620 (exists $category_font_color{$category} ? (-fill => $category_font_color{$category}) : ()), 6621 (exists $category_font{$category} ? (-font => $category_font{$category}) : ()), 6622 ); 6623 if (exists $category_font{$category} && 6624 $category_font{$category} =~ /%d/) { 6625 my $bbox_area = get_bbox_area($item); 6626 # XXX bessere Abstufungen 6627 if ($bbox_area < 1500) { 6628 $args{-font} = sprintf $category_font{$category}, 7; 6629 } elsif ($bbox_area > 5000) { 6630 $args{-font} = sprintf $category_font{$category}, 12; 6631 } else { 6632 $args{-font} = sprintf $category_font{$category}, 10; 6633 } 6634 } 6635 6636 if (!$no_overlap_label{$abk} || 6637 !draw_text_intelligent 6638 ($c, $mx, $my, 6639 %args, 6640 -abk => $abk_fg, 6641 -xadd => $xadd_anchor, 6642 -yadd => $yadd_anchor, 6643 -outline => 1, 6644 )) { 6645 my($mx,$my) = ($mx,$my); 6646 if (defined $label_spaceadd) { 6647 $args{-text} = $label_spaceadd . $args{-text}; 6648 $args{-anchor} = "w"; 6649 } elsif (# shift to right for points, 6650 # center for polygons 6651 @coordlist == 2 || $abk eq 'v') { 6652 $mx += $xadd_anchor->{'w'}; 6653 $my += $yadd_anchor->{'w'}; 6654 $args{-anchor} = "w"; 6655 } 6656 outline_text($c, $mx, $my, %args); 6657 } 6658 }; 6659 6660 my $draw_street_photo = sub { 6661 my($street_photo, $anchor, $delta, %opts) = @_; 6662 my $addtag = delete $opts{-addtag}; 6663 my($mx,$my) = get_polyline_center(@coordlist); 6664 6665 if ($delta) { 6666 # atan2(y2-y1, x2-x1) 6667 my $ii = 2; # second point 6668 my $alpha = atan2($coordlist[$ii+1]-$coordlist[$ii-1], $coordlist[$ii]-$coordlist[$ii-2]); 6669 my $beta = $alpha - pi()/2; 6670 my($dx, $dy) = (-$delta*cos($beta), -$delta*sin($beta)); 6671 $mx += $dx; 6672 $my += $dy; 6673 } 6674 6675 $c->createImage($mx,$my, 6676 -anchor => $anchor, 6677 -image => $street_photo, 6678 # $abk-img or $abk-fg ? 6679 -tags => [$abk,$strname,"$abk-img", 6680 "$abk-" . $i, 6681 ($addtag ? $addtag : ()), 6682 ]); 6683 if ($street_photo eq $steigung_photo) { 6684 if ($strname =~ /([\d\.]+)\s*%/) { 6685 outline_text 6686 ($c, 6687 $mx, $my, 6688 -anchor => "n", 6689 -text => "$1%", 6690 -font => $font{'small'}, 6691 -tags => [$abk,$strname,"$abk-fg", 6692 "$abk-" . $i, 6693 ($addtag ? $addtag : ()), 6694 ], 6695 -outlinewidth => 2, 6696 ); 6697 } 6698 } 6699 }; 6700 6701 if ($cat_hin =~ /^F:(.*)$/) { # Fl�che, no $cat_rueck handling here 6702 $category = $1; 6703 my($color, $rest) = split(/\|/, $category, 2); 6704 my $stipple = ($layer_category_stipple{$abk} && $layer_category_stipple{$abk}{$category}) || $layer_stipple{$abk} || $category_stipple{$category}; 6705 if (defined $rest && $rest ne "") { 6706 if ($rest =~ $complex_IMG_qr) { 6707 $image = $1; 6708 $anchor = $2 if $2; 6709 } elsif (!defined $stipple) { 6710 $stipple = $rest; 6711 } 6712 } 6713 if ($color eq 'I') { $abk = 'i' } # Inseln 6714 $color = ($layer_category_color{$abk} && $layer_category_color{$abk}{$color}) || $category_color{$color} || $color; 6715 $stipple = load_stipple($stipple) if $stipple; 6716 if ($str_outline{$abk} && @coordlist > 2) { 6717 $item = $c->createPolygon 6718 (@coordlist, 6719 -fill => $outline_color{$abk}, 6720 -outline => $outline_color{$abk}, 6721 -width => 2, 6722 -tags => ["$abk-out", "$abk-$category-out"], 6723 ); 6724 } 6725 if (@coordlist == 2) { 6726 # dicken Punkt zeichnen 6727 $item = $c->createLine 6728 (@coordlist, @coordlist, 6729 -fill => $color, 6730 -width => 5, # XXX skalieren 6731 -capstyle => $capstyle_round, 6732 -tags => [$abk, $strname, $kreuzungen[0], 6733 $abk."-".$i 6734 ], 6735 ); 6736 } else { 6737 $item = $c->createPolygon 6738 (@coordlist, 6739 -fill => $color, 6740 ($stipple ? (-stipple => $stipple) : ()), 6741 -tags => [$abk, $strname, 6742 "$abk-$category",$abk."-".$i], 6743 ); 6744 } 6745 6746 if ($str_name_draw{$abk}) { 6747 $draw_strname_for_area->(); 6748 } 6749 6750 if (($abk eq 'v' && $star_photo) || $image) { 6751 $sight_draw->(); 6752 } 6753 6754 } elsif ($cat_hin =~ $complex_IMG_qr) { 6755 my $img_spec = $1; 6756 my $anchor = ($2 ? $2 : "c"); 6757 my $p; 6758 my $img = maybe_expand_image_file($img_spec, $str_file{$abk}, "data"); 6759 if (!$img) { 6760 # XXX get_image_for_str is actually more powerful, and should maybe replace maybe_expand_image_file+image_from_file? 6761 $p = get_image_for_str($img_spec, $img_spec, $abk); 6762 } else { 6763 $p = image_from_file($top, $img); 6764 } 6765 # XXX this is leaking (photo never deleted...) 6766 # XXX $abk-XXX => $abk-fg or $abk-img ? 6767 # XXX use $abk-fg for now (scaling works!) 6768 if ($p) { 6769 $item = $c->createImage(@coordlist[0..1], 6770 -image => $p, 6771 -anchor => $anchor, 6772 -tags => [$abk, $strname, 6773 "$abk-fg", "$abk-" . $i], 6774 ); 6775 } else { 6776 warn "Can't find photo $img (2)"; 6777 } 6778 } elsif ($use_stippleline == 1) { # old stipple code 6779 # XXX no $cat_rueck handling here (this code branch is anyway obsolete) 6780 # min. 4 Koordinaten erzwingen 6781 @coordlist == 2 && push(@coordlist, @coordlist); 6782 6783 Tk::StippleLine::create 6784 ($c, @coordlist, 6785 -fill => $this_color_hin, 6786 -width => $this_width_hin, 6787 -joinstyle => 'bevel', 6788 -tags => [$abk, $strname, 6789 "$abk-$cat_hin", "$abk-" . $i], 6790 ); 6791 6792 } else { # points or lines 6793 if (@coordlist == 2) { # point 6794 # Points do not have $cat_rueck 6795 if ($abk eq 'v') { 6796 TRY_IMAGE: { 6797 if ($cat_hin =~ /\|IMG:([^|]+)/) { 6798 $image = $1; 6799 } elsif ($star_photo) { 6800 $image = undef; # default to $star_photo 6801 } else { 6802 last TRY_IMAGE; 6803 } 6804 $sight_draw->(); 6805 return; # next loop 6806 } 6807 } elsif ($achtung_photo && grep { $_ eq 'danger' } @addinfo_hin) { 6808 $draw_street_photo->($achtung_photo, "c"); 6809 } elsif ($abk eq 'w' && $cat_hin eq 'I' && $strname ne '') { 6810 # only draw label 6811 # XXX quick hack, really only needed for osm islands 6812 my %args = (-text => $strname, 6813 -tags => ["i-label", $strname], 6814 (exists $category_font_color{$category} ? (-fill => $category_font_color{$category}) : ()), 6815 (exists $category_font{$category} ? (-font => $category_font{$category}) : ()), 6816 -font => sprintf($category_font{$cat_hin}, 10), 6817 -outlinewidth => 2); 6818 outline_text($c, @coordlist, %args); 6819 return; 6820 } elsif ($cat_hin =~ $roundabout_qr) { 6821 $draw_street_photo->($kreisverkehr_photo, "c"); 6822 } elsif ($cat_hin =~ $viewangle_qr) { 6823 my($start,$extent) = ($1,$2); 6824 my $radius = get_line_width("$abk-View"); 6825 my @coords = ((map { $_-$radius } @coordlist), 6826 (map { $_+$radius } @coordlist)); 6827 my @common_args = (-outline => undef, 6828 -fill => "red", 6829 -tags => [$abk, $strname, 6830#XXX fix category from View:...:... to View? 6831 "$abk-View", "$abk-" . $i, 6832 @extra_tags], 6833 ); 6834 if (abs($extent) < 30) { 6835 $c->createArc(@coords, @common_args, 6836 -start => $start, 6837 -extent => $extent, 6838 ); 6839 } else { 6840 my $delta = $extent > 0 ? 30 : -30; 6841 my $end = $start + $extent; 6842 for(my $_start = $start; $extent > 0 ? $_start < $end : $_start > $end; $_start+=$delta) { 6843 $c->createArc(@coords, @common_args, 6844 -start => $_start, 6845 -extent => $delta/2, 6846 ); 6847 } 6848 } 6849 return; # next loop 6850 } 6851 6852 # dicken Punkt zeichnen 6853 my $width = $category_point_size{$cat_hin} || 5; # XXX skalieren 6854 $item = $c->createLine(@coordlist, @coordlist, 6855 -fill => $this_color_hin, 6856 -width => $width, 6857 -capstyle => $capstyle_round, 6858 -tags => [$abk, $strname, 6859 $abk."-".$cat_hin, $abk."-".$i, 6860 @extra_tags], 6861 ); 6862 } else { # lines 6863 my @std_tags_hin = ($abk, $strname,$abk."-".$cat_hin,$abk."-".$i); 6864 my @std_tags_rueck; 6865 my $line_dash_hin = (exists $layer_category_line_dash{$abk} && $layer_category_line_dash{$abk}{$cat_hin}) || $layer_line_dash{$abk} || $category_dash{$cat_hin} || $line_dash{$abk}; 6866 my $line_dash_rueck; 6867 my $line_capstyle_hin = (exists $layer_category_capstyle{$abk} && $layer_category_capstyle{$abk}{$cat_hin}) || $layer_line_capstyle{$abk} || $category_capstyle{$cat_hin} || $line_capstyle{$abk}; 6868 my $line_capstyle_rueck; 6869 if ($cat_rueck) { 6870 @std_tags_rueck = @std_tags_hin; 6871 $std_tags_rueck[2] = "$abk-$cat_rueck"; 6872 $line_dash_rueck = (exists $layer_category_line_dash{$abk} && $layer_category_line_dash{$abk}{$cat_rueck}) || $layer_line_dash{$abk} || $category_dash{$cat_rueck} || $line_dash{$abk}; 6873 $line_capstyle_rueck = (exists $layer_category_capstyle{$abk} && $layer_category_capstyle{$abk}{$cat_rueck}) || $layer_line_capstyle{$abk} || $category_capstyle{$cat_rueck} || $line_capstyle{$abk}; 6874 } 6875 my $stipple = ($layer_category_stipple{$abk} && $layer_category_stipple{$abk}{$category}) || $layer_stipple{$abk} || $category_stipple{$category}; 6876 $stipple = load_stipple($stipple) if $stipple; 6877 if (@addinfo_hin) { # ignore @addinfo_rueck for now 6878 for my $addinfo_hin (@addinfo_hin) { 6879 if ($addinfo_hin =~ $tunnel_qr) { 6880 $line_dash_hin = $line_dash{"Tu"}; 6881 $line_dash_rueck = $line_dash_hin if defined $line_dash_hin; 6882 draw_tunnel_entrance(\@coordlist, -width => $this_width_hin+4, -tags => \@std_tags_hin, -mounds => $addinfo_hin); 6883 } elsif ($addinfo_hin eq 'Br') { 6884 draw_bridge(\@coordlist, -width => $this_width_hin+4, -tags => \@std_tags_hin); 6885 } 6886 } 6887 } 6888 if (!$use_stippleline) { 6889 undef $line_dash_hin; 6890 } 6891 if ($str_outline{$abk}) { 6892 # XXX no $cat_rueck support yet for outlines 6893 $c->createLine 6894 (@coordlist, 6895 -fill => $outline_color{$abk}, 6896 -width => $this_width_hin+2, 6897 -joinstyle => 'bevel', 6898 -tags => ["$abk-out", 6899 "$abk-$cat_hin-out"], 6900 ($line_dash_hin ? (-dash => $line_dash_hin) : ()), 6901 ($line_capstyle_hin ? (-capstyle => $line_capstyle_hin) : ()), 6902 ($stipple ? (-stipple => $stipple) : ()), 6903 (exists $layer_category_line_arrow{$abk} && exists $layer_category_line_arrow{$abk}{$cat_hin} ? (-arrow => $layer_category_line_arrow{$abk}{$cat_hin}) 6904 : exists $layer_line_arrow{$abk} ? (-arrow => $layer_line_arrow{$abk}) 6905 : exists $category_line_arrow{$cat_hin} ? (-arrow => $category_line_arrow{$cat_hin}) : ()), 6906 ); 6907 } 6908 if (defined $cat_rueck) { 6909 my $delta = $this_width_hin/2; # XXX need a better rule for this 6910 my($cl_hin,$cl_rueck) = offset_line(\@coordlist, $delta, $cat_hin ne '', $cat_rueck ne ''); 6911 for my $dir (1, -1) { 6912 my($cl, $this_color, $this_width, $cat, $std_tags, $line_dash, $line_capstyle); 6913 if ($dir == 1 && $cat_hin ne '') { 6914 $this_color = $this_color_hin; 6915 $this_width = $this_width_hin/2; 6916 $cat = $cat_hin; 6917 $cl = $cl_hin; # XXX del: [@coordlist]; 6918 $std_tags = \@std_tags_hin; 6919 $line_dash = $line_dash_hin; 6920 $line_capstyle = $line_capstyle_hin; 6921 } elsif ($dir == -1 && $cat_rueck ne '') { 6922 $this_color = $this_color_rueck; 6923 $this_width = $this_width_rueck/2; 6924 $cat = $cat_rueck; 6925 $cl = []; 6926 for(my $cl_i = $#$cl_rueck-1; $cl_i >= 0; $cl_i-=2) { 6927 push @$cl, @{$cl_rueck}[$cl_i, $cl_i+1]; 6928 } 6929 $std_tags = \@std_tags_rueck; 6930 $line_dash = $line_dash_rueck; 6931 $line_capstyle = $line_capstyle_rueck; 6932 } else { 6933 next; 6934 } 6935# my $delta = -$this_width; 6936# 6937# for(my $ii = 2; $ii < $#$cl; $ii+=2) { 6938# # atan2(y2-y1, x2-x1) 6939# my $alpha = atan2($cl->[$ii+1]-$cl->[$ii-1], $cl->[$ii]-$cl->[$ii-2]); 6940# my $beta = $alpha - pi()/2; 6941# my($dx, $dy) = ($delta*cos($beta), $delta*sin($beta)); 6942# $cl->[$ii] += $dx; 6943# $cl->[$ii+1] += $dy; 6944# if ($ii == 2) { 6945# $cl->[0] += $dx; 6946# $cl->[1] += $dy; 6947# } 6948# } 6949 $c->createLine 6950 (@$cl, 6951 -fill => $this_color, 6952 -width => $this_width, 6953 -joinstyle => 'bevel', 6954 -tags => [@$std_tags, 6955 @extra_tags], 6956 ($line_dash ? (-dash => $line_dash) : ()), 6957 ($line_capstyle ? (-capstyle => $line_capstyle) : ()), 6958 ($stipple ? (-stipple => $stipple) : ()), 6959 #(exists $category_line_arrow{$cat} ? (-arrow => $category_line_arrow{$cat}) : ()), 6960 # XXX Tk problem? bad rendering with capstyle=>"round" and arrow=>something 6961 -arrow => ($line_capstyle && $line_capstyle eq 'round' ? "none" : "last"), 6962 ); 6963 6964 # Draw an extra point indicating the point of action for CP/CP2 items 6965 if ($cat_hin =~ m{^( CP | CP2 | PI )$}x) { 6966 my @center = $cat_hin eq 'CP' ? @{$cl}[2,3] : @{$cl}[0,1]; 6967 $c->createOval((map { $_-5 } @center), (map { $_+5 } @center), # XXX skalieren 6968 -outline => $this_color_hin, 6969 -width => 2, 6970 -tags => [@$std_tags, @extra_tags], 6971 ); 6972 } 6973 6974 } 6975 } elsif ($cat_hin eq 'Br') { 6976 draw_bridge(\@coordlist, -width => $this_width_hin+4, -tags => \@std_tags_hin); 6977 } elsif ($cat_hin =~ $roundabout_qr) { 6978 if ($edit_normal_mode) { 6979 $c->createLine(@coordlist, 6980 -fill => 'blue', 6981 -width => 2, 6982 -tags => [@std_tags_hin, @extra_tags], 6983 -dash => [1,4], 6984 ); 6985 $draw_street_photo->($kreisverkehr_photo, "c"); 6986 } else { 6987 # ignore lined roundabouts in renderer 6988 return; 6989 } 6990 } elsif ($cat_hin =~ $tunnel_qr) { 6991 draw_tunnel_entrance(\@coordlist, -width => $this_width_hin+4, -tags => \@std_tags_hin, -mounds => $cat_hin); 6992 } else { 6993 $item = $c->createLine 6994 (@coordlist, 6995 -fill => $this_color_hin, 6996 -width => $this_width_hin, 6997 -joinstyle => 'bevel', 6998 -tags => [@std_tags_hin, 6999 @extra_tags], 7000 ($stipple ? (-stipple => $stipple) : ()), 7001 ($line_dash_hin ? (-dash => $line_dash_hin) : ()), 7002 ($line_capstyle_hin ? (-capstyle => $line_capstyle_hin) : ()), 7003 (exists $layer_category_line_arrow{$abk} && exists $layer_category_line_arrow{$abk}{$cat_hin} ? (-arrow => $layer_category_line_arrow{$abk}{$cat_hin}) 7004 : exists $layer_line_arrow{$abk} ? (-arrow => $layer_line_arrow{$abk}) 7005 : exists $category_line_arrow{$cat_hin} ? (-arrow => $category_line_arrow{$cat_hin}) : ()), 7006 ); 7007 } 7008 7009 if ($abk eq 'sBAB') { # thin grey line for "two track" effect 7010 $c->createLine 7011 (@coordlist, 7012 -fill => 'lightgrey', 7013 -width => 1, 7014 -joinstyle => 'bevel', 7015 -tags => [$abk, $strname, $abk."-fg",$abk."-".$i], 7016 ($line_dash_hin ? (-dash => $line_dash_hin) : ()), 7017 # XXX??? ($line_dash_rueck ? (-capstyle => $line_dash_rueck) : ()), 7018 -state => ($this_width_hin >= $sBAB_two_track_width ? 'normal' : 'hidden'), 7019 ); 7020 } 7021 7022 if ($str_name_draw{$abk} && $category eq 'Z' && $item) { 7023 $draw_strname_for_area->(); 7024 } 7025 7026 # no $cat_rueck support for names 7027 if ($str_name_draw{$abk} 7028 && (($abk =~ /^[ls]/ && 7029 $abk ne 'sBAB' && 7030 ($cat_hin =~ /^[BH]/ || 7031 ($lazy_str{$abk} && $scale >= 10) 7032 )) || 0) # nur Hauptstra�en zeichnen (wg. Performance 7033 # und �bersichtlichkeit), oder auch Nebenstra�en, 7034 # falls lazy_plot und kleiner Ma�stab 7035 ) { 7036 my $strname = Strassen::strip_bezirk($strname); 7037 Tk::RotFont::canvas 7038 ($c, $abk, \@coordlist, 7039 $category_rot_font{$cat_hin} || $rot_font_sub, 7040 $category_size{$cat_hin} || 10, 7041 $strname, 7042 (defined $category_font_color{$cat_hin} ? (-fill => $category_font_color{$cat_hin}) : ()), 7043 ); 7044 } 7045 if ($str_nr_draw{$abk}) { 7046 draw_street_numbers($c,$strname,$abk,\@coordlist); 7047 } 7048 7049 my $street_photo; 7050 my $street_anchor = "nw"; 7051 my $street_delta; 7052 my $street_addtag; 7053 if ($abk eq 'e') { 7054 my $p = get_symbol_scale($abk); 7055 $street_photo = $p if $p; 7056 } elsif ($cat_hin eq 'St') { 7057 $street_photo = $steigung_photo if $steigung_photo; 7058 $street_anchor = "s"; 7059 $street_delta = $street_photo->width/2+2; 7060 } elsif ($abk eq 'comm-tram' || $abk eq 'nl') { 7061 $street_photo = get_symbol_scale($abk); 7062 $street_delta = 0; # XXX 7063 } elsif (@addinfo_hin # ignore @addinfo_rueck for now 7064 ) { 7065 for my $addinfo_hin (@addinfo_hin) { 7066 if ($addinfo_hin eq 'inwork') { 7067 $street_photo = get_symbol_scale('attrib-inwork'); 7068 $street_addtag = "attrib-inwork"; 7069 } elsif ($addinfo_hin eq 'danger' && $achtung_photo) { 7070 $street_photo = $achtung_photo; 7071 $street_anchor = "c"; 7072 } 7073 } 7074 } 7075 if ($street_photo) { 7076 $draw_street_photo->($street_photo, $street_anchor, $street_delta, -addtag => $street_addtag); 7077 } 7078 } 7079 } 7080 } 7081 }; 7082EOF 7083 7084 # XXX maybe combine this code with parsing coords code in $plotstr_draw_sub 7085 my $parse_coords_code = <<'EOF'; 7086 TRY: { 7087#XXX my($xx, $yy); 7088 if (!$edit_mode) { 7089 ($xx, $yy) = split /,/, $_; 7090 } elsif ($edit_mode && 7091 /([A-Za-z]+)?(-?[\d\.]+),(-?[\d\.]+)$/) { 7092 # XXX Verwendung von data/BASE (hier und �berall) 7093 my $this_coordsys = (defined $1 ? $1 : ''); 7094 if ($this_coordsys eq $coordsys || 7095 (!($this_coordsys ne '' || $coordsys ne 'B'))) { 7096 ($xx, $yy) = ($2, $3); 7097 } else { 7098 # the hard way: convert it 7099 $this_coordsys = 'B' if $this_coordsys eq ''; 7100 ($xx,$yy) = $Karte::map_by_coordsys{$this_coordsys}->map2map($coord_system_obj, $2, $3); 7101#warn "($xx,$yy)"; 7102 } 7103 } else { 7104 last TRY; 7105 } 7106 } 7107EOF 7108 7109 $plotpoint_draw_sub = <<'EOF' 7110 sub { 7111 my $ret = shift; 7112 my $category = $ret->[Strassen::CAT]; 7113 return if defined $restrict and $category !~ /$restrict/; 7114 if (!$edit_normal_mode) { # we want to see everything in edit mode 7115 return if index($category, "::igndisp") >= 0; 7116 } 7117 my $pointname = $ret->[Strassen::NAME]; 7118 my $koord = $ret->[Strassen::COORDS][0]; # erste Koordinate 7119 $koord = $conv->($koord) if $conv; 7120 my($xx,$yy); 7121 $_ = $koord; 7122EOF 7123 . $parse_coords_code . <<'EOF'; 7124 my($x, $y) = transpose($xx, $yy); 7125 7126 if ($layer_category_image{$abk} && defined $layer_category_image{$abk}{$category}) { 7127 $category = "IMG:$layer_category_image{$abk}{$category}"; 7128 } elsif (defined $category_image{$category}) { 7129 $category = "IMG:$category_image{$category}"; 7130 } 7131 DRAW_ITEM: { 7132 if ($category =~ $complex_IMG_qr) { 7133 my $photo = $1; 7134 my $anchor = ($2 ? $2 : "c"); 7135 my($base) = ($photo =~ m|/| ? $photo =~ /([^\/]+)$/ : $photo); 7136 $base = "p_$base"; 7137 my $p = get_image_for_p($base, $photo, $abk); 7138 if ($p) { 7139 $c->createImage($x, $y, -image => $p, 7140 -anchor => $anchor, 7141 # $abk-img or $abk-fg? set both! 7142 -tags => ["$abk-img", "$xx,$yy", $pointname, ($abk =~ /^L\d+$/ ? ("$abk-fg", "L-fg") : ())], 7143 ); 7144 last; # we're done, only label drawing missing 7145 } 7146 warn "Can't find image $photo (3)"; 7147 } 7148 7149 if ($XXX_use_old_R_symbol && $abk eq 'r') { 7150 my $length = $category =~ m{^(RP)$} ? $rbahn_length/2 : $rbahn_length; 7151 $c->createLine($x-$length, $y, $x+$length, $y, 7152 -tags => ["$abk-bg", "$xx,$yy", $pointname, "$abk-" . $category . "-bg"]); 7153 if ($category !~ m{^(RP)$}) { 7154 $c->createText($x, $y, 7155 -tags => ["$abk-fg", "$xx,$yy", $pointname, "$abk-" . $category . "-fg"]); 7156 } 7157 } elsif ($abk =~ /^[ubr]$/) { 7158 $c->createImage($x, $y, -tags => ["$abk-fg", "$xx,$yy", $pointname, "$abk-" . $category . "-fg"]); 7159 } elsif ($abk eq 'lsa') { 7160 my($rawcategory, @attribs) = split /::/, $category; 7161 my @tags = ("$abk-fg", "$xx,$yy", $pointname, 7162 "$abk-" . $rawcategory . "-fg", 7163 $abk."-".$i); 7164 # keine Verwendung von _coord_as_string 7165 $c->createImage 7166 ($x, $y, 7167 -image => ($rawcategory eq 'B' 7168 ? $andreaskr_photo 7169 : $rawcategory eq 'B0' 7170 ? $andreaskr_grey_photo 7171 : $rawcategory eq 'Zbr' 7172 ? $zugbruecke_photo 7173 : $rawcategory eq 'F' 7174 ? $ampelf_photo 7175 : $ampel_photo 7176 ), 7177 -tags => \@tags, 7178 ); 7179 if (@attribs) { 7180 for my $attrib (@attribs) { 7181 if ($attrib eq 'inwork') { 7182 my $use_inwork_photo = get_symbol_scale('attrib-inwork'); 7183 if ($use_inwork_photo) { 7184 $c->createImage($x, $y, 7185 -anchor => 'nw', 7186 -image => $use_inwork_photo, 7187 -tags => [@tags,'attrib-inwork']); 7188 } 7189 } 7190 } 7191 } 7192 $ampeln{"$xx,$yy"} = $rawcategory; 7193 } elsif ($abk eq 'pl') { 7194 $c->createLine($x, $y, $x, $y, 7195 -tags => ["$abk-fg", "$xx,$yy", $pointname], 7196 ); 7197 } elsif ($abk eq 'vf') { 7198 my($rawcategory, $attribs) = split /::/, $category; 7199 my @tags = ("$abk-fg", "$xx,$yy", "$abk-$rawcategory-fg", "$abk-$i"); 7200 if ($rawcategory eq 'Vf') { 7201 my($x1,$y1,$x2,$y2,$x3,$y3) = 7202 (transpose(@{Strassen::to_koord1($ret->[Strassen::COORDS][0])}), 7203 transpose(@{Strassen::to_koord1($ret->[Strassen::COORDS][1])}), 7204 transpose(@{Strassen::to_koord1($ret->[Strassen::COORDS][2])})); 7205 $c->createImage($x2,$y2, -tags => \@tags); 7206 my $len1 = Strassen::Util::strecke([$x1,$y1], [$x2,$y2]); 7207 my $whole_len1 = $len1 > 20 ? 20 : $len1; 7208 my $len2 = Strassen::Util::strecke([$x2,$y2], [$x3,$y3]); 7209 my $whole_len2 = $len2 > 20 ? 20 : $len2; 7210 my($cx1,$cy1,$cx2,$cy2,$cx3,$cy3) 7211 = (($x1-$x2)/$len1*$whole_len1+$x2, 7212 ($y1-$y2)/$len1*$whole_len1+$y2, 7213 $x2,$y2, 7214 ($x3-$x2)/$len2*$whole_len2+$x2, 7215 ($y3-$y2)/$len2*$whole_len2+$y2, 7216 ); 7217 $c->createLine($cx1,$cy1,$cx2,$cy2,$cx3,$cy3, 7218 -tags => "$abk-bg"); 7219 } else { 7220 $c->createImage($x,$y, -tags => \@tags); 7221 } 7222 } elsif ($abk =~ /^L(\d+)/) { 7223 my $color = $category =~ /^\#/ ? $category : exists $layer_category_color{$abk} && exists $layer_category_color{$abk}{$category} ? $layer_category_color{$abk}{$category} : exists $category_color{$category} ? $category_color{$category} : undef; 7224 my $width = ($layer_category_line_width{$abk} && $layer_category_line_width{$abk}{$category}) || $category_width{$category} || $p_width{$abk} || $default_width || 6; 7225 $c->createLine($x, $y, $x, $y, 7226 (defined $color ? (-fill => $color) : ()), 7227 -width => $width, 7228 -tags => ["$abk-fg", "$xx,$yy", $pointname, "p-" . $i, "L-fg"]); 7229 } elsif ($abk =~ /^(kn|ki|rest)$/) { 7230 $c->createImage($x, $y, 7231 -tags => ["$abk-fg", "$xx,$yy", $pointname, "$abk-" . $i]); 7232 } elsif ($abk =~ /^label/) { 7233 # $category should contain font, anchor etc. 7234 $c->createText($x, $y, -text => $pointname, 7235 -font => $font{'large'}, # XXX 7236 -anchor => "w", # XXX 7237 -tags => ["$abk-fg", "$xx,$yy", $pointname, "$abk-" . $i]); 7238 } else { 7239 # Else draw a generic point (broad, color from cat) 7240 my $color = $category_color{$category} || ($category =~ /^\#/ ? $category : 'red'); 7241 my $width = $category_width{$category} || $p_width{$abk} || $default_width || 6; 7242 $c->createLine($x, $y, $x, $y, 7243 -fill => $color, -capstyle => $capstyle_round, 7244 -width => $width, 7245 -tags => ["$abk-fg", "$xx,$yy", $pointname, "$abk-" . $i]); 7246 } 7247 } # DRAW_ITEM 7248 if ($name_draw) { 7249 my %args = ((exists $category_font_color{$category} ? (-fill => $category_font_color{$category}) : ()), 7250 (exists $category_font{$category} ? (-font => $category_font{$category}) : ()), 7251 -outlinewidth => 2, 7252 -text => $pointname, 7253 -tags => $name_draw_tag, 7254 ); 7255 if ($orientation eq 'portrait' && $Tk::VERSION >= 800) { 7256 require Tk::RotFont; 7257 # XXX geht nicht... 7258 Tk::RotFont::createRotText 7259 ($c, $x, $y, 7260 -text => $pointname, 7261 -rot => 3.141592653/2, 7262 #-font => get_orte_label_font($cat), 7263 -font => $rot_font_sub->(100), # no $cat... 7264 -tags => $name_draw_tag, 7265 ); 7266 } elsif (!$no_overlap_label || 7267 !draw_text_intelligent 7268 ($c, $x, $y, 7269 -abk => $name_draw_other, 7270 -xadd => $xadd_anchor, 7271 -yadd => $yadd_anchor, 7272 -outline => 1, 7273 %args, 7274 )) { 7275 my($x,$y) = ($x,$y); 7276 if (defined $label_spaceadd) { 7277 $args{-text} = $label_spaceadd . $args{-text}; 7278 } else { 7279 $x += $xadd_anchor->{'w'}; 7280 $y += $yadd_anchor->{'w'}; 7281 } 7282 outline_text($c, $x, $y, -anchor => 'w', %args); 7283 } 7284 } 7285 }; 7286EOF 7287 7288 $plotorte_draw_sub = <<'EOF' 7289 sub { 7290 my $ret = shift; 7291 my $cat = $ret->[Strassen::CAT]; 7292 my($name, $add) = split(/\|/, $ret->[Strassen::NAME]); 7293 my($xx,$yy); 7294 $_ = $ret->[Strassen::COORDS][0]; 7295 $_ = $conv->($_) if $conv; 7296EOF 7297 . $parse_coords_code . <<'EOF'; 7298# if ($ret->[Strassen::COORDS][0] =~ /(-?\d+),(-?\d+)/) { 7299 if (defined $xx) { 7300# my($x, $y) = ($1, $2); 7301# my($tx, $ty) = $transpose->($x, $y); 7302 my($tx, $ty) = $transpose->($xx, $yy); 7303 my $fullname = ($add ? $name . " " . $add : $name); 7304 return if ($place_category && $place_category ne "auto" && $cat < $place_category); 7305 my $point_item; 7306 if (!$municipality) { 7307 $point_item = $c->createLine 7308 ($tx, $ty, $tx, $ty, 7309 -tags => [$type, "$xx,$yy", $fullname, $label_tag."P$cat", $type."-".($i-1)], 7310 ); 7311 } 7312 if ($name_o) { 7313 my $text = ($args{Shortname} 7314 ? $name 7315 : $fullname); 7316 my(@tags) = ($label_tag, "$label_tag$cat", $label_tag."-".($i-1)); 7317 if ($orientation eq 'portrait' && $Tk::VERSION >= 800) { 7318 require Tk::RotFont; 7319 # XXX geht nicht... 7320 Tk::RotFont::createRotText 7321 ($c, $tx, $ty-4, 7322 -text => $text, 7323 -rot => 3.141592653/2, 7324 #-font => get_orte_label_font($cat), 7325 -font => $rot_font_sub->(100+$cat*12), 7326 -tags => \@tags, 7327 ); 7328 } elsif ($no_overlap_label && !$municipality) { 7329 push(@orte_coords_labeling, 7330 [$text, $tx, $ty, $cat, $point_item]); 7331 } else { 7332 if ($do_outline_text) { 7333 outline_text 7334 ($c, 7335 $tx+4, 7336 $ty, 7337 -text => $text, 7338 -tags => \@tags, 7339 -anchor => 'w', 7340 -justify => 'left', 7341 -fill => '#000080', 7342 -font => get_orte_label_font($cat), 7343 ); 7344 } else { 7345 $c->createText($tx, $ty, 7346 -text => $label_spaceadd{'o'} . $text, 7347 -tags => \@tags, 7348 ); 7349 } 7350 } 7351 } 7352 } 7353 }; 7354EOF 7355} 7356 7357sub maybe_expand_image_file { 7358 my($imgfile, $datafile, $subdir) = @_; 7359 if (file_name_is_absolute($imgfile)) { 7360 return try_image_suffix($imgfile); 7361 } 7362 my $abs_img = try_image_suffix("$FindBin::RealBin/$subdir/$imgfile"); 7363 if (defined $abs_img && -r $abs_img) { 7364 return $abs_img; 7365 } 7366 # relative to this file 7367 return try_image_suffix(dirname($datafile) . "/" . $imgfile); 7368} 7369 7370# For an absolute image path without suffix try to find an existing 7371# image which is supported by the current configuration. Returns undef 7372# if nothing suitable could be found. 7373sub try_image_suffix { 7374 my($imgfile_without_suffix) = @_; 7375 return $imgfile_without_suffix if $imgfile_without_suffix =~ m{\.(png|jpg|xpm|gif|svg)$}; 7376 for my $suffix (@image_type_order) { 7377 my $try_imgfile = $imgfile_without_suffix.".".$suffix; 7378 if (can_handle_image_suffix($suffix) && -r $try_imgfile) { 7379 return $try_imgfile; 7380 } 7381 } 7382 undef; 7383} 7384 7385# Return true if the supplied image suffix ("jpg", "gif" etc.) can be 7386# handled. The result is cached in the global %can_handle_image. 7387sub can_handle_image_suffix { 7388 my $suffix = shift; 7389 if (!defined $can_handle_image{$suffix}) { 7390 if ($suffix eq 'png') { 7391 if (eval { 7392 die "Probably corrupt in my SiePerl distribution" if $os eq 'win' && $Tk::VERSION < 804; 7393 require Tk::PNG; 7394 1; 7395 }) { 7396 $can_handle_image{$suffix} = 1; 7397 } else { 7398 $can_handle_image{$suffix} = 0; 7399 } 7400 } elsif ($suffix eq 'jpg') { 7401 if (eval { 7402 die "Probably corrupt in my SiePerl distribution" if $os eq 'win' && $Tk::VERSION < 804; 7403 require Tk::JPEG; 7404 1; 7405 }) { 7406 $can_handle_image{$suffix} = 1; 7407 } else { 7408 $can_handle_image{$suffix} = 0; 7409 } 7410 } elsif ($suffix eq 'svg') { 7411 # Assume that a postprocessor will be run to create the 7412 # real image 7413 if (can_handle_image_suffix('png') && eval { 7414 require File::Temp; 7415 is_in_path('convert'); 7416 }) { 7417 $can_handle_image{$suffix} = 1; 7418 } else { 7419 $can_handle_image{$suffix} = 0; 7420 } 7421 } elsif ($suffix =~ m{^(gif|xpm)$}) { # Tk builtins 7422 $can_handle_image{$suffix} = 1; 7423 } else { 7424 die "Unhandled image suffix '$suffix'"; 7425 } 7426 } 7427 $can_handle_image{$suffix}; 7428} 7429 7430sub set_bindings { 7431 foreach (qw(p pp o 7432 u-bg u-fg u_bg-img b-bg b-fg b_bg-img r-bg r-fg r_bg-img 7433 sperre sperre_u sperre_b sperre_r 7434 lsa-fg lsa-bg show pl-fg 7435 L-img L-fg kn-fg ki-fg rest-fg)) { 7436 std_p_binding($_); 7437 } 7438 7439 foreach (qw(s sBAB S l L u b r f v v-fg w W i e comm mount), 7440 (map { "comm-$_" } @comments_types), 7441 qw(gr qs hs ql hl fz nl ovl temp_sperre temp_sperre_s rw wr)) { 7442 std_str_binding($_); 7443 } 7444 7445 # XXX Some bindings are here and in std_p_binding, which cause 7446 # problems as both function set the <Leave> binding 7447 # XXX route: no! 7448 # XXX more missing, typically everything with a label is transparent 7449 foreach (qw(lsa-bg lsa-fg vf-bg vf-fg 7450 s-label-bg s-label sBAB-label-bg sBAB-label 7451 w-label-bg w-label f-label-bg f-label gBO-label-bg gBO-label 7452 l-label-bg l-label 7453 u-label b-label r-label fz-label show O), 7454 (map { ("comm-$_-label", "comm-$_-label-bg") } @comments_types), 7455 ) { 7456 std_transparent_binding($_); 7457 } 7458 # spezielle Bindings f�r Routen 7459 $c->bind('route', '<Any-Enter>' => sub { enterroute($_[0]) }); 7460 $c->bind('route', '<Any-Motion>' => sub { enterroute($_[0]) }); 7461 $c->bind('route', '<Any-Leave>' => \&leaveroute); 7462 7463 # Cursor bei delnet-Kreuzen: 7464 $c->bind("delnet", "<Any-Enter>" => sub { 7465 if ($map_mode eq MM_USEREDIT) { 7466 save_cursor(); 7467 set_cursor("addnet", "tcross"); 7468 } 7469 }); 7470 $c->bind("delnet", "<Any-Leave>" => \&restore_cursor); 7471 7472 foreach (qw(all)) { 7473 # XXX TODO should be ButtonRelease-1 some day, if using 7474 # B1-Motion for rubberbanding a zoom region 7475 if ($MM_DRAG_IS_OBSOLETE) { 7476 $c->bind($_, "<ButtonRelease-1>" => \&set_route_point); 7477 } else { 7478 $c->bind($_, "<ButtonPress-1>" => \&set_route_point); 7479 } 7480 } 7481 7482 # Stack in tkstadtware f�r dragging angucken! XXX 7483 $c->CanvasBind("<1>" => sub { 7484 if ($MM_DRAG_IS_OBSOLETE) { 7485 my $e = $c->XEvent; 7486 ($canvas_drag_x, $canvas_drag_y) = ($e->x, $e->y); 7487 $c->scan('mark', $canvas_drag_x, $canvas_drag_y); 7488 $maybe_canvas_drag = 1; 7489 } 7490 7491 if ($map_mode =~ /^BBBike/) { 7492 my $button_callback = $map_mode . '::button'; 7493 if (defined &$button_callback) { 7494 my $e = $c->XEvent; 7495 my $ret = eval $button_callback.'($_[0], $e)'; 7496 die $@ if $@; 7497 return if $ret; # otherwise fallthrough to MM_DRAG 7498 } 7499 } elsif ($map_mode eq MM_CUSTOMCHOOSE) { 7500 set_route_point($c); 7501 } elsif ($map_mode eq MM_SCRIBBLE) { 7502 # XXX not Tk::Babybike! 7503 Tk::Babybike::handle_button1_scribble($c,$c->XEvent); 7504 } elsif ($map_mode eq MM_URL_SELECT) { 7505 my($url) = grep { $_ } map { 7506 my($url) = $_ =~ m{((?:file|https?)://\S+)}; 7507 defined $url ? $url : undef; 7508 } $c->gettags("current"); 7509 if ($url) { 7510 require WWWBrowser; 7511 main::status_message("URL: $url", "info"); 7512 WWWBrowser::start_browser($url); 7513 } else { 7514 warn "Cannot get URL from " . join(", ", $c->gettags("current")); 7515 } 7516 } 7517 7518 # XXX duplicated code, see above 7519 if ($map_mode eq MM_DRAG) { 7520 my $e = $c->XEvent; 7521 ($canvas_drag_x, $canvas_drag_y) = ($e->x, $e->y); 7522 $c->scan('mark', $canvas_drag_x, $canvas_drag_y); 7523 $maybe_canvas_drag = 1; 7524 } 7525 }); 7526 $c->CanvasBind('<B1-Motion>' => sub { 7527 if ($map_mode eq MM_SCRIBBLE) { 7528 # XXX not Tk::Babybike! 7529 return Tk::Babybike::handle_button1_motion_scribble($c,$c->XEvent); 7530 } 7531 return if $map_mode ne MM_DRAG && !$MM_DRAG_IS_OBSOLETE; 7532 my $e = $c->XEvent; 7533 my($e_x, $e_y) = ($e->x, $e->y); 7534 # Start drag only if the user has moved a certain 7535 # distance (3 pixels here). This is because clicking 7536 # the mouse may involve a small motion movement. 7537 return if ($maybe_canvas_drag && 7538 Strassen::Util::strecke([$canvas_drag_x, $canvas_drag_y],[$e_x, $e_y]) < 3); 7539 $maybe_canvas_drag = 0; 7540 $c->scan('dragto', $e_x, $e_y, 1); 7541 if (!$c->{SavedCursor}) { 7542 save_cursor(); 7543 set_cursor('movehand','fleur'); 7544 } 7545 $in_canvas_drag = 1; 7546 }); 7547 $c->CanvasBind('<ButtonRelease-1>' => sub { 7548 restore_cursor(); 7549 $in_canvas_drag = 0; 7550 }); 7551 7552 set_b2(); 7553 7554 # Canvas menu 7555 my $popup_menu; 7556 if ($right_is_popup) { 7557 $popup_menu = $c->Menu(-title => M"Kartenmen�", 7558 -tearoff => $Tk::platform eq 'unix'); 7559 $popup_menu->command(-label => M"Gesamte Route l�schen", 7560 -command => sub { delete_route() }, 7561 ); 7562 $popup_menu->command(-label => M"Suche wiederholen", 7563 -command => \&re_search_gui, 7564 ); 7565 $popup_menu->command(-label => M"R�ckweg", 7566 -command => \&way_back, 7567 ); 7568 } 7569 if ($c->can("menu") and $c->can("PostPopupMenu") and $Tk::VERSION >= 800) { 7570 $c->menu($popup_menu); 7571 $c->Tk::bind('<3>' => sub { 7572 if ($right_is_popup) { 7573 my $e = $_[0]->XEvent; 7574 $_[0]->PostPopupMenu($e->X, $e->Y); 7575 } else { 7576 delete_route(); 7577 } 7578 }); 7579 } else { 7580 # legacy code 7581 $frame->bind($c, "<ButtonPress-3>" => sub { 7582 if ($right_is_popup) { 7583 my $e = $_[0]->XEvent; 7584 $popup_menu->Post($e->X, $e->Y); 7585 } else { 7586 delete_route(); 7587 } 7588 }); 7589 } 7590 $top->Advertise(PopupMenu => $popup_menu) 7591 if $popup_menu; 7592 7593 my $alt_mouse1 = sub { 7594## DEBUG_BEGIN 7595#benchbegin("Alt Mouse1"); 7596## DEBUG_END 7597 7598 if ($map_mode eq MM_DRAG || $MM_DRAG_IS_OBSOLETE) { 7599 my $e = $c->XEvent; 7600 ($canvas_drag_x, $canvas_drag_y) = ($e->x, $e->y); 7601 $c->scan('mark', $canvas_drag_x, $canvas_drag_y); 7602 $maybe_canvas_drag = 1; 7603 } 7604 7605 if ($alt_set_route_point{$map_mode}) { 7606 return $alt_set_route_point{$map_mode}->(@_); 7607 } 7608 my($rx,$ry); 7609 if ($map_mode eq MM_BUTTONPOINT) { 7610 ($rx,$ry) = freerec_sub(@_); 7611 } 7612 freedraw_sub($_[0],$rx,$ry); 7613## DEBUG_BEGIN 7614#benchend(); 7615## DEBUG_END 7616 }; 7617 7618 foreach (qw(Alt Shift Lock)) { 7619 $frame->bind($c, "<$_-ButtonPress-1>" => $alt_mouse1); 7620 } 7621 7622 if ($followmouse) { 7623 start_followmouse(); 7624 } 7625 7626 # Zoom 7627 for my $kp ('plus', 'KP_Add') { 7628 $top->bind("<$kp>" => sub { scalecanvas_from_canvas_event($c, 2) }); 7629 } 7630 for my $kp ('minus', 'KP_Subtract') { 7631 $top->bind("<$kp>" => sub { scalecanvas_from_canvas_event($c, 0.5) }); 7632 } 7633 7634 $top->protocol('WM_DELETE_WINDOW', \&exit_app_noninteractive); 7635 my($old_width, $old_height); 7636 my $in_configure_event; 7637 $top->bind('<Configure>' => sub { 7638 my $e = $top->XEvent; 7639 return if !$e || $in_configure_event; 7640 $in_configure_event++; 7641 eval { 7642 if (!defined $old_width || $old_width != $e->w || 7643 !defined $old_height || $old_height != $e->h) { 7644 arrange_symframe(); 7645 arrange_topframe(); 7646 $old_width = $e->w; 7647 $old_height = $e->h; 7648 } 7649 }; 7650 my $err = $@; 7651 $in_configure_event--; 7652 die $err if $err; 7653 }); 7654 7655 $top->bind("<<CloseMainWin>>" => \&exit_app); 7656 for my $mod (qw(Alt Control)) { 7657 $top->bind("<$mod-r>" => sub { reload_all() }); 7658 } 7659 7660 $top->bind('<Control-o>' => sub { load_save_route(0) }); 7661 $top->bind('<Control-s>' => sub { load_save_route(1) }); 7662 $top->bind('<Control-underscore>' => \&get_undo_route); 7663 $top->bind('<Control-z>' => \&get_undo_route); 7664 $top->bind($_ => sub { 7665 require BBBikeAdvanced; 7666 search_anything(); 7667 }) 7668 for ('<Control-Key-f>', '<Key-slash>'); 7669 $top->bind('<Control-g>' => sub { send_route_to_gps() }); 7670 $top->bind('<Key-colon>' => sub { my $e = $c->XEvent; 7671 my(%args); 7672 if ($e) { 7673 my ($x, $y) = ($c->canvasx($e->x), 7674 $c->canvasy($e->y)); 7675 $args{-preserveposition} = [$x,$y]; 7676 } 7677 enter_scale(%args); 7678 }); 7679 7680 $top->bind("<Escape>" => sub { $escape = 1 }); 7681 $top->bind('Busy', '<Escape>' => sub { $escape = 1; }); 7682 $top->bind('Busy', '<KeyRelease-Escape>' => sub { }); 7683 bind_nomod($top, '<asterisk>' => \&show_register); 7684 for my $i (0 .. 9) { 7685 my $ii = $i; 7686 $top->bind("<Key-$ii>" => sub { get_route_from_register($ii) }); 7687 } 7688 7689 bind_nomod($top, "<P>" => sub { 7690 require BBBikeAdvanced; 7691 start_ptksh(); 7692 }); 7693 ## XXX Duplicate binding! 7694 #$top->bind("<Control-R>" => sub { 7695 # require BBBikeAdvanced; 7696 # reload_new_modules(); 7697 # }); 7698 bind_nomod($top, "<S>" => sub { 7699 set_map_mode(MM_SEARCH); 7700 }); 7701 bind_nomod($top, "<U>" => sub { 7702 $map_mode = MM_USEREDIT; 7703 set_cursor('delnet', 'X_cursor'); 7704 }); 7705 if ($Tk::platform ne 'MSWin32') { # XXX aber auf der Win98-Maschine von Monika laeuft es gut?! 7706 bind_nomod($top, "<X>" => \&layer_editor); 7707 } 7708 bind_nomod($top, "<i>" => sub { show_info() }); 7709 7710 if (!$no_map) { 7711 bind_nomod($top, '<Key-M>' => sub { $map_draw = 1; getmap() }); 7712 $top->bind('<Control-Key-M>' => sub { delete_map() }); 7713 } 7714 7715 $top->bind("<BackSpace>" => \&mouse_dellast); 7716 $top->bind("<Shift-BackSpace>" => \&delete_route); 7717 $top->bind("<Control-Key-x>" => \&delete_route); 7718 $top->bind("<Delete>" => \&deltovia); 7719 7720 if ($advanced) { 7721 advanced_bindings(); 7722 } 7723 7724 for my $kp ('', 'KP_') { 7725 eval { # perl/Tk+win definiert keine KP_-Keysyms 7726 $top->bind("<${kp}Down>" => sub { $c->yview(scroll => 1, 'units') }); 7727 $top->bind("<${kp}Up>" => sub { $c->yview(scroll => -1, 'units') }); 7728 $top->bind("<${kp}Left>" => sub { $c->xview(scroll => -1, 'units') }); 7729 $top->bind("<${kp}Right>" => sub { $c->xview(scroll => 1, 'units') }); 7730 7731 $top->bind("<${kp}Begin>" => sub { center_best() }); 7732 }; 7733 } 7734 7735 $top->bind("<Next>" => sub { $c->yview(scroll => 5, 'units') }); 7736 $top->bind("<Prior>" => sub { $c->yview(scroll => -5, 'units') }); 7737 $top->bind("<Home>" => sub { $c->xview(scroll => -5, 'units') }); 7738 $top->bind("<End>" => sub { $c->xview(scroll => 5, 'units') }); 7739 eval { 7740 $top->bind("<KP_Next>" => sub { $c->xview(scroll => 1, 'units'); 7741 $c->yview(scroll => 1, 'units') }); 7742 $top->bind("<KP_Prior>" => sub { $c->xview(scroll => 1, 'units'); 7743 $c->yview(scroll => -1, 'units') }); 7744 $top->bind("<KP_Home>" => sub { $c->xview(scroll => -1, 'units'); 7745 $c->yview(scroll => -1, 'units') }); 7746 $top->bind("<KP_End>" => sub { $c->xview(scroll => -1, 'units'); 7747 $c->yview(scroll => 1, 'units') }); 7748 }; 7749 7750 $top->bind("<Shift-KP_2>" => sub { $c->yview(scroll => 5, 'units') }); 7751 $top->bind("<Shift-KP_8>" => sub { $c->yview(scroll => -5, 'units') }); 7752 $top->bind("<Shift-KP_4>" => sub { $c->xview(scroll => -5, 'units') }); 7753 $top->bind("<Shift-KP_6>" => sub { $c->xview(scroll => 5, 'units') }); 7754 7755 $top->bind("<Shift-KP_3>" => sub { $c->xview(scroll => 5, 'units'); 7756 $c->yview(scroll => 5, 'units') }); 7757 $top->bind("<Shift-KP_9>" => sub { $c->xview(scroll => 5, 'units'); 7758 $c->yview(scroll => -5, 'units') }); 7759 $top->bind("<Shift-KP_7>" => sub { $c->xview(scroll => -5, 'units'); 7760 $c->yview(scroll => -5, 'units') }); 7761 $top->bind("<Shift-KP_1>" => sub { $c->xview(scroll => -5, 'units'); 7762 $c->yview(scroll => 5, 'units') }); 7763 7764 # Cycling through toplevels 7765 $top->bind("all", "<Control-Tab>" => sub { focus_next_toplevel(); Tk->break }); 7766 $top->bind(".", "<Control-Tab>" => sub { }); 7767 $top->bind("all", "<Control-Shift-Tab>" => sub { focus_prev_toplevel(); Tk->break }); 7768 $top->bind(".", "<Control-Shift-Tab>" => sub { }); 7769 7770} 7771 7772sub focus_next_toplevel { _focus_nextprev_toplevel(+1) } 7773sub focus_prev_toplevel { _focus_nextprev_toplevel(-1) } 7774 7775sub _focus_nextprev_toplevel { 7776 my($dir) = @_; 7777 my @all_toplevels = grep { Tk::Exists($_) && $_->state eq "normal" } ($top, values(%toplevel)); 7778 my $current_toplevel = $top->focusCurrent->toplevel; 7779 my $new_i; 7780 for(my $i=0; $i<=$#all_toplevels;$i++) { 7781 if ($all_toplevels[$i] == $current_toplevel) { 7782 $new_i = $i + $dir; 7783 last; 7784 } 7785 } 7786 if (!defined $new_i) { 7787 $new_i = 0; 7788 warn "cannot find current toplevel <$current_toplevel> in list <@all_toplevels>, fallback to main window <$top>"; 7789 } else { 7790 if ($new_i < 0) { 7791 $new_i = $#all_toplevels; 7792 } elsif ($new_i > $#all_toplevels) { 7793 $new_i = 0; 7794 } 7795 } 7796 $all_toplevels[$new_i]->raise; 7797 # ->focus between toplevels does not seem to work under cygwin/x 7798 $all_toplevels[$new_i]->focus; 7799} 7800 7801sub set_map_mode { 7802 if (@_) { 7803 $map_mode = $_[0]; 7804 } 7805 execute_and_set_map_mode_deactivate(undef); 7806 if ($map_mode eq MM_SEARCH) { 7807 if (defined $search_route_flag && $search_route_flag =~ /^ziel/) { 7808 set_cursor('ziel'); 7809 } else { 7810 set_cursor('start'); 7811 } 7812 } elsif ($map_mode eq MM_BUTTONPOINT) { 7813 set_cursor('xy','crosshair'); 7814 } elsif ($map_mode eq MM_INFO) { 7815#XXX $map_mode_deactivate->() if $map_mode_deactivate; 7816 set_cursor('info','circle'); 7817#XXX undef $map_mode_deactivate; 7818 } elsif ($map_mode eq MM_DRAG) { 7819 set_cursor('movehand','fleur'); 7820 } elsif (exists $map_mode_callback{$map_mode} && 7821 ref $map_mode_callback{$map_mode} eq 'CODE') { 7822 $map_mode_callback{$map_mode}->(); 7823 } elsif ($map_mode eq MM_URL_SELECT) { 7824 set_cursor('www'); 7825 } 7826} 7827 7828sub execute_and_set_map_mode_deactivate { 7829 my($new_sub) = @_; 7830 if ($map_mode_deactivate) { 7831 $map_mode_deactivate->(); 7832 undef $map_mode_deactivate; 7833 } 7834 if ($new_sub) { 7835 $map_mode_deactivate = $new_sub; 7836 } 7837} 7838 7839# Bindings 7840# ... unter Mauszeiger anzeigen 7841# Punkte 7842sub std_p_binding { 7843 my $tag = $_[0]; 7844 $c->bind($tag, '<Any-Enter>' => sub { 7845 $layer_pre_enter_command{$tag}->() 7846 if exists $layer_pre_enter_command{$tag}; 7847 enterpoint($_[0]); 7848 $layer_post_enter_command{$tag}->() 7849 if exists $layer_post_enter_command{$tag}; 7850 }); 7851 unless (/^lsa-/) { # lsa-fg/bg: leavepoint wird unten gesetzt 7852 $c->bind($tag, '<Any-Leave>' => sub { 7853 $layer_pre_leave_command{$tag}->() 7854 if exists $layer_pre_leave_command{$tag}; 7855 leavepoint(@_); 7856 $layer_post_leave_command{$tag}->() 7857 if exists $layer_post_leave_command{$tag}; 7858 }); 7859 } 7860} 7861# Strecken, Fl�chen 7862sub std_str_binding { 7863 my $tag = $_[0]; 7864 $c->bind($tag, '<Any-Enter>' => sub { 7865 $layer_pre_enter_command{$tag}->() 7866 if exists $layer_pre_enter_command{$tag}; 7867 enterstr($_[0]); 7868 $layer_post_enter_command{$tag}->() 7869 if exists $layer_post_enter_command{$tag}; 7870 }); 7871 $c->bind($tag, '<Any-Leave>' => sub { 7872 $layer_pre_leave_command{$tag}->() 7873 if exists $layer_pre_leave_command{$tag}; 7874 leavestr($_[0]); 7875 $layer_post_leave_command{$tag}->() 7876 if exists $layer_post_leave_command{$tag}; 7877 }); 7878 if (defined $c_balloon) { 7879 # Need to check if *all* items under the cursor are the same, as we 7880 # create the balloon text from *all* canvas items. This uses some 7881 # logic found in balloon_info_from_all_tags 7882 use vars qw($old_current_str_items); 7883 $old_current_str_items = "" if !defined $old_current_str_items; 7884 my $closeenough = $balloon_info_from_all_tags_closeenough; 7885 $c->bind($tag, '<Any-Motion>' => sub { 7886 my($c) = @_; 7887 my $e = $c->XEvent; 7888 my($xx, $yy) = ($c->canvasx($e->x), $c->canvasy($e->y)); 7889 my(@items) = $c->find(overlapping => 7890 $xx-$closeenough, $yy-$closeenough, 7891 $xx+$closeenough, $yy+$closeenough); 7892 my $new_current_str_items = join(" ", @items); 7893 if ($new_current_str_items ne $old_current_str_items) { 7894 enterstr($c); 7895 $old_current_str_items = $new_current_str_items; 7896 } else { 7897 $c_balloon->Track; 7898 } 7899 }); 7900 } 7901} 7902 7903# unter den Tags nachgucken, ob es eine Stra�e zum Anzeigen gibt 7904# ("durchsichtige" Tags) 7905sub std_transparent_binding { 7906 # Motion statt Enter, da sich die Stra�e unter einer Route 7907 # �ndern kann. 7908 $c->bind($_[0], '<Any-Motion>' => sub { 7909 my $str = show_below_route_str($_[0]); 7910 if (defined $str && $str ne '' 7911 && defined $c_balloon 7912 && $use_c_balloon >= 2) { 7913 # XXX before each $c_ballon->Popup should be this line (maybe move into sub?): 7914 if ($leave_after) { $leave_after->cancel; undef $leave_after } 7915 if (1) { $str = balloon_info_from_all_tags($c) } 7916 if (defined $str) { $c_balloon->Popup($str); } # XXX if defined 7917 } 7918 }); 7919 if ($_[0] =~ /^(show$|lsa-)/) { # XXX this special handling should go away 7920 $c->bind($_[0], '<Any-Leave>' => sub { &leavepoint; 7921 &leavestr; } ); 7922 } else { 7923 $c->bind($_[0], '<Any-Leave>' => \&leavestr); 7924 } 7925} 7926 7927# Aufzeichnen eines Punktes 7928sub freerec_sub { 7929 my $e = $_[0]->XEvent; 7930 my($xx, $yy) = ($c->canvasx($e->x), $c->canvasy($e->y)); 7931 require BBBikeAdvanced; 7932 buttonpoint(anti_transpose($xx, $yy)); 7933} 7934 7935# freies Zeichnen von Punkten 7936sub freedraw_sub { 7937 my($w, $ax, $ay) = @_; 7938 my($xx, $yy); 7939 if (defined $ax && defined $ay) { 7940 ($xx, $yy) = transpose($ax, $ay); 7941 } else { 7942 my($e) = $w->XEvent; 7943 ($xx, $yy) = ($c->canvasx($e->x), $c->canvasy($e->y)); 7944 ($ax, $ay) = anti_transpose($xx, $yy); 7945 } 7946 return if !defined(addpoint_xy($ax, $ay, $xx, $yy)); 7947 push @search_route_points, [join(",",@{ $realcoords[-1] }), POINT_MANUELL]; 7948 if ($net && $map_mode ne MM_BUTTONPOINT) { 7949 push @act_search_route, 7950 $net->route_to_name([$realcoords[-2], $realcoords[-1]], 7951 -startindex => $#realcoords+1); 7952 add_new_point($net, join(",",@{ $realcoords[-1] }), -quiet => 1); 7953 } 7954 if ($map_mode ne MM_BUTTONPOINT) { 7955 set_flag('via'); 7956 set_flag('ziel'); 7957 set_cursor('ziel'); 7958 $search_route_flag = 'ziel_cont'; 7959 } 7960 updatekm(); 7961 if (!$edit_mode && !$edit_normal_mode) { 7962 update_route_strname(); 7963 } 7964} 7965 7966# Letzten Punkt l�schen 7967sub mouse_dellast { 7968 if ($special_edit ne '') { 7969 eval $special_edit . '_edit_mouse3(@_)'; 7970 die $@ if $@; 7971 } else { 7972 dellast() 7973 } 7974} 7975 7976# delete_route light. Allerdings nicht ganz klar, wo das hier warum 7977# verwendet wird. 7978sub reset_button_command { 7979 reset_undo_route(); 7980 undef $search_route_flag; 7981 if ($map_mode eq MM_SEARCH) { 7982 search_route_mouse(1); 7983 } 7984} 7985 7986sub change_net_type { 7987 undef $handicap_s_net; 7988 if ($net_type eq "r") { 7989 *set_coords = \&set_coords_rbahn; 7990 } elsif ($net_type eq "us") { 7991 *set_coords = \&set_coords_usbahn; 7992 } elsif ($net_type eq "rus") { 7993 *set_coords = \&set_coords_bahn; 7994 } elsif ($net_type eq 'wr') { 7995 *set_coords = \&set_coords_wasserrouten; 7996 if (!$str_draw{wr}) { 7997 plot("str", "wr", -draw => 1); 7998 } 7999 } elsif ($net_type eq 'custom') { 8000 if (!keys %custom_net_str) { 8001 require BBBikeAdvanced; 8002 select_layers_for_net_dialog(); 8003 } 8004 *set_coords = \&set_coords_custom; 8005 } else { 8006 *set_coords = \&set_coords_str; 8007 } 8008 if (defined $net) { 8009 make_net(); 8010 } 8011} 8012 8013# Routenpunkt festlegen 8014sub set_route_point { 8015 return if $in_canvas_drag; 8016 my $e = $_[0]->XEvent; 8017 # auf Alt, Shift und CapsLock checken 8018 # bei Win95/NT ist 8 nicht CapsLock, sondern NumLock 8019 if ($Tk::VERSION < 800) { 8020 return if $e->s & (1+2+($os eq 'win' ? 0 : 8)); 8021 } else { 8022 return if $e->s =~ /\b(Shift|Alt|Lock)-/; 8023 } 8024 if ($MM_DRAG_IS_OBSOLETE) { 8025 $c->scan('mark', $e->x, $e->y); 8026 } 8027 if ($map_mode eq MM_EDITPOINT) { 8028 my(@tags) = $c->gettags('current'); 8029 if ($tags[0] eq 'pp' || $tags[0] =~ /^vf/ || $tags[0] =~ /^lsa/) { 8030 $point_editor->set($tags[1]); 8031 } 8032 } elsif ($map_mode eq MM_INSERTPOINT) { 8033 insert_point_from_canvas($c); 8034 } elsif ($map_mode eq MM_CREATERELATION) { 8035 create_relation_from_canvas($c); 8036 } elsif ($map_mode eq MM_DRAG) { 8037 $c->scan('mark', $e->x, $e->y); 8038 } elsif ($special_edit ne '') { 8039 eval $special_edit . '_edit_mouse1(@_)'; 8040 die $@ if $@; 8041 } elsif ($map_mode eq MM_CUSTOMCHOOSE_TAG || $map_mode eq MM_CUSTOMCHOOSE) { 8042 $customchoosecmd->($c, $e); 8043 } elsif ($map_mode eq MM_SEARCH) { # XXX doppelt 8044 #XXX defined $search_route_flag && ???? 8045 if (defined $search_route_flag && $search_route_flag eq 'ziel_cont') { 8046 search_route_mouse_cont(); 8047 } elsif ($search_route_flag) { 8048 search_route_mouse(); 8049 } else { 8050 warn "XXX activating...."; 8051 $search_route_flag = "start"; 8052 search_route_mouse(); 8053 } 8054 Tk->break; # XXX insert more Tk->break in this subroutine? 8055 } elsif ($map_mode eq MM_BUTTONPOINT) { 8056 my $item = 'current'; 8057 my(@tags) = $c->gettags($item); 8058 if ($tags[0] !~ /^(pp|o)$/) { 8059 ($item) = find_below($c, "pp", "o"); 8060 if (!defined $item) { 8061 warn "Not over a <pp> or <o> point, got @tags"; 8062 return; 8063 } 8064 } 8065 require BBBikeAdvanced; 8066 my($rx,$ry) = buttonpoint(undef,undef,$item); 8067 freedraw_sub($_[0],$rx,$ry); 8068 } elsif ($map_mode eq MM_INFO) { 8069 show_info(); 8070 } elsif ($map_mode =~ /^BBBike/) { 8071 my $itembutton_callback = $map_mode . '::itembutton'; 8072 if (defined &$itembutton_callback) { 8073 eval $itembutton_callback.'($c,$e)'; 8074 die $@ if $@; 8075 } 8076 } elsif ($map_mode eq MM_USEREDIT) { 8077 user_edit_street(); 8078 Tk->break; # XXX insert more Tk->break in this subroutine? 8079 } elsif ($set_route_point{$map_mode}) { 8080 $set_route_point{$map_mode}->($e); 8081 } elsif ($map_mode ne MM_SEARCH) { 8082 addpoint_inter(); 8083 } 8084} 8085 8086sub draw_street_numbers { 8087 # the coloring is german specific 8088 my($c,$strname,$abk,$coordlist_ref) = @_; 8089 use constant SMALLER_TABLES => 0.7; 8090 my $do_round = 0; 8091 my($type, $image, $nr); 8092 if ($city_obj->can("parse_street_type_nr")) { 8093 ($type, $nr, $do_round, $image) = $city_obj->parse_street_type_nr($strname); 8094 } 8095 if (!defined $type) { 8096 # XXX handling of multiple street numbers? e.g. "F1, R1" or "B2/B5"? 8097 ($type,$nr) = Strasse::parse_street_type_nr($strname); 8098 } 8099 if (defined $type) { 8100 my $dist = 0; 8101 my $drawn = 0; 8102 my $draw_sub = sub { 8103 my $coord_i = shift; 8104 my($midx,$midy) = Strassen::Util::middle(@{$coordlist_ref}[$coord_i..$coord_i+3]); 8105 # XXX make public if 8106 # XXX * I find a way of resizing for larger scales 8107 # XXX * I should check the legal status of all these logos 8108 if ($devel_host && defined $image && (my $p = get_image("strnr_$type", $datadir."/comments_route_img/$image"))) { 8109 $c->createImage 8110 ($midx,$midy,-image => $p, 8111 -tags => "$abk-label"); # no strnr (only for images) and strnr-$item here 8112 } else { 8113 my($item, $r_item); 8114 # XXX It seems that at least the BAB number is off by maybe half a pixel, 8115 # but it's not possible in Tk to set subpixel positions. 8116 $item = $c->createText 8117 ($midx,$midy, 8118 -text => ($type =~ /^(B|BAB|DK|DW)$/ ? "" : $type) . (defined $nr ? $nr : ""), 8119 -font => $scale < SMALLER_TABLES ? $font{'tiny'} : $font{'normal'}, 8120 -fill => ($do_round ? 'white' : 8121 $type =~ /^(BAB|DK)$/ ? 'white' : 8122 $type =~ /^(F|R)$/ ? 'green4' : 8123 'black'), 8124 -tags => "$abk-label"); # no strnr (only for images) and strnr-$item here 8125 my(@bbox) = $c->bbox($item); 8126 if ($do_round) { 8127 $r_item = $c->createOval 8128 ($bbox[0]-2,$bbox[1]-2,$bbox[2]+2,$bbox[3]+2, 8129 -fill => '#90d090', 8130 -outline => 'black', 8131 -width => 1, 8132 -tags => ["$abk-label-bg", "strnr", "strnr-$item"], 8133 ); 8134 } elsif ($type =~ m{^( B | BAB | DK | DW)$}x) { 8135 my $size = $scale < SMALLER_TABLES ? 16 : 32; 8136 my $p; 8137 # prefer png because of alpha 8138 if ($type eq 'B' || $type eq 'DW') { 8139 $p = get_image("strnr_B$size", "bundesstrasse_table_$size.png"); 8140 } elsif ($type eq 'BAB') { 8141 $p = get_image("strnr_BAB$size", "bab_table_$size.png"); 8142 } elsif ($type eq 'DK') { 8143 $p = get_image("strnr_DK$size", "droga_krajowa_table_$size.png"); 8144 } 8145 if ($p) { 8146 # Manually corrected (-1/-1) to look with my standard font 8147 # (lucida sans ...) 8148 $r_item = $c->createImage(int(($bbox[2]+$bbox[0])/2) - ($size > 16 ? 1 : 0), 8149 int(($bbox[3]+$bbox[1])/2) - ($size > 16 ? 1 : 0), 8150 -image => $p, 8151 -tags => ["$abk-label-bg", "strnr", "strnr-$item"], 8152 ); 8153 } else { 8154 # XXX fallback to createRectangle below 8155 warn "Cannot get image for strnr_" . $type . $size; 8156 } 8157 } else { 8158 $r_item = $c->createRectangle 8159 ($bbox[0]-2,$bbox[1]-2,$bbox[2]+2,$bbox[3]+2, 8160 -fill => ($type eq 'B' ? 'yellow' : 8161 ($type eq 'BAB' ? 'blue' : 8162 'white')), 8163 -outline => ($type eq 'BAB' ? 'white' : 8164 ($type =~ /^(F|R)$/ ? 'green4' : 'black')), 8165 -width => 2, 8166 -tags => ["$abk-label-bg", "strnr", "strnr-$item"], 8167 ); 8168 } 8169 $c->raise($item,$r_item); 8170 } 8171 $dist = 0; 8172 $drawn++; 8173 }; 8174 8175 for(my $ci=2; $ci<$#$coordlist_ref; $ci+=2) { 8176 $dist += Strassen::Util::strecke([@{$coordlist_ref}[$ci-2,$ci-1]], [@{$coordlist_ref}[$ci,$ci+1]]); 8177 if ($dist >= 400) { # should be in the magnitude of canvas height 8178 $draw_sub->($ci-2); 8179 } 8180 } 8181 if (!$drawn) { 8182 $draw_sub->(int($#$coordlist_ref/4)*2); # XXX ueberdenken 8183 } 8184 } 8185} 8186 8187# middle mouse button bindings 8188sub set_b2 { 8189 # first delete all canvas b2 bindings 8190 foreach my $bind (qw(ButtonPress-2 2 B2-Motion)) { 8191 $c->CanvasBind("<$bind>" => ''); 8192 } 8193 if ($b2_mode == B2M_DELLAST) { 8194 $c->CanvasBind("<ButtonPress-2>" => \&mouse_dellast); 8195 } elsif ($b2_mode == B2M_AUTOSCROLL) { 8196 require Tk::Autoscroll; 8197 my %extra_args; 8198 $extra_args{'-speed'} = $autoscroll_speed if ($autoscroll_speed); 8199 $extra_args{'-middle'} = !!$autoscroll_middle; 8200 Tk::Autoscroll::Init($c, %extra_args); 8201 } elsif ($b2_mode == B2M_SCAN || $b2_mode == B2M_FASTSCAN) { 8202 my $gain = $b2_mode == B2M_SCAN ? 1 : 10; 8203 $c->CanvasBind('<2>', 8204 [sub { 8205 my($w,$x,$y) = @_; 8206 $w->scan('mark',$x,$y); 8207 },Tk::Ev('x'),Tk::Ev('y')]); 8208 $c->CanvasBind('<B2-Motion>', 8209 [sub { 8210 my($w,$x,$y) = @_; 8211 $w->scan('dragto',$x,$y,$gain); 8212 },Tk::Ev('x'),Tk::Ev('y')]); 8213 } elsif ($b2_mode == B2M_CUSTOM && $b2m_customcmd) { 8214 $c->CanvasBind('<2>', [$b2m_customcmd, $c]); 8215 $c->CanvasBind('<B2-Motion>', ''); 8216 } else { 8217 # no bindings 8218 } 8219 set_mouse_desc(); 8220} 8221 8222# Setzen der Hilfstexte f�r die Maustastenbelegung 8223sub enter_leave_bind_for_help { 8224 my($w, $textref) = @_; 8225 my(@save_mouse_text); 8226 $w->bind 8227 ('<Enter>' => sub { 8228 for my $i (1..3) { 8229 if (defined $textref->[$i-1]) { 8230 $save_mouse_text[$i] = $mouse_text[$i] || ''; 8231 $mouse_text[$i] = $textref->[$i-1]; 8232 } 8233 } 8234 }); 8235 $w->bind 8236 ('<Leave>' => sub { 8237 for my $i (1..3) { 8238 if (defined $save_mouse_text[$i]) { 8239 $mouse_text[$i] = $save_mouse_text[$i]; 8240 undef $save_mouse_text[$i]; 8241 } 8242 } 8243 }); 8244} 8245 8246sub set_datadir { 8247 my($newdir, %args) = @_; 8248 if ($args{-clearold}) { 8249 @Strassen::datadirs = (); 8250 } 8251 if (defined $newdir && -d $newdir) { 8252 unshift @Strassen::datadirs, $newdir; 8253 $datadir = $newdir; 8254 } else { 8255 $datadir = $Strassen::datadirs[0]; 8256 } 8257 if ($verbose) { 8258 print STDERR Mfmt("Aktuelles Datenverzeichnis ist %s\n", $datadir); 8259 } 8260 8261 my $metafile = "$newdir/meta.dd"; 8262 if (-r $metafile) { 8263 require Geography::FromMeta; 8264 $city_obj = Geography::FromMeta->load_meta($metafile); 8265 } 8266 8267 # XXX The polar_coord_hack for osm2bbd 8268 if (-e "$datadir/Karte/Polar.pm") { 8269 lib->import($datadir); 8270 } 8271} 8272 8273# Beendet die Anwendung. Bei Bedarf werden Konfigurationsdateien gesichert. 8274# Tempor�re Dateien werden gel�scht. 8275sub exit_app { 8276 8277 if (Tk::Exists($top) && $ask_quit && $Tk::VERSION >= 800) { 8278 # deiconify seems to be required on Solaris CDE 8279 $top->deiconify; 8280 # XXX and raise makes the thing slow on KDE :-( 8281 $top->raise; 8282 return if ($top->messageBox 8283 (-icon => "question", 8284 -title => M"BBBike beenden", 8285 -message => M"Soll BBBike beendet werden?", 8286 -type => "YesNo") =~ /no/i); # XXX Sprache? 8287 } 8288 8289 exit_app_noninteractive(); 8290} 8291 8292sub exit_app_noninteractive { 8293 save_last_loaded($last_loaded_obj); 8294 save_last_loaded($last_loaded_layers_obj) if $last_loaded_layers_obj; 8295 8296 if ($autosave_opts && defined $opt) { 8297 # get actual geometry 8298 $geometry = fix_geometry(); 8299 # get actual font parameters 8300 if ($top->can("fontActual")) { 8301 my %f_attr = $top->fontActual($font{'normal'}); 8302 $font_family = $f_attr{-family}; 8303 $font_size = $f_attr{-size}; 8304 $font_weight = $f_attr{-weight}; 8305 } 8306 # Reference power/speed 8307 my $speed_or_power = ($active_speed_power{Type} eq 'speed' 8308 ? \@speed 8309 : \@power 8310 ); 8311 $speed_power_reference_string = $active_speed_power{Type} . ":" . $speed_or_power->[$active_speed_power{Index}]; 8312 # save options 8313 eval { 8314 $opt->save_options; 8315 }; 8316 if ($@) { 8317 status_message($@, "warn"); 8318 } 8319 } 8320 8321 if (defined &BBBikeServer::server_cleanup) { 8322 BBBikeServer::server_cleanup(); 8323 } 8324 8325 my @todel; 8326 if (keys %tmpfiles) { 8327 push @todel, keys %tmpfiles; 8328 if ($INC{'GfxConvert.pm'}) { 8329 push @todel, keys %GfxConvert::tmpfiles; 8330 } 8331 } 8332 unlink @todel if (@todel); 8333 $top->destroy if Tk::Exists($top); 8334 exit; 8335} 8336 8337###################################################################### 8338 8339# Ver�ndern der aktuellen Default-Geschwindigkeit oder Default-Leistung. 8340# $type ist entweder "speed" oder "power" 8341# $index ist der zu �nderne Eintrag 8342sub change_active_speed_power { 8343 my($type, $index) = @_; 8344 my $has_old = 0; 8345 if (keys %active_speed_power) { 8346 # delete old 8347 my $frame = ($active_speed_power{Type} eq 'speed' 8348 ? \@speed_frame 8349 : \@power_frame 8350 ); 8351 my $inx = $active_speed_power{Index}; 8352 if (defined $frame->[$inx]) { 8353 $frame->[$inx]->configure(-relief => "raised", 8354 -borderwidth => 1); 8355 } 8356 $has_old = 1; 8357 } 8358 8359 %active_speed_power = (Type => $type, 8360 Index => $index); 8361 8362 # set new 8363 my $frame = ($active_speed_power{Type} eq 'speed' 8364 ? \@speed_frame 8365 : \@power_frame 8366 ); 8367 my $inx = $active_speed_power{Index}; 8368 if (defined $frame->[$inx]) { 8369 $frame->[$inx]->configure(-relief => "raised", 8370 -borderwidth => 2); 8371 } 8372 8373 calc_ampel_optimierung() if $ampel_optimierung; 8374 8375 redraw_path() if $has_old; 8376} 8377 8378sub change_ampel_count { 8379 my($type, $index) = @_; 8380 $ampel_count->{$type}[$index] = !$ampel_count->{$type}[$index]; 8381 if ($ampel_count->{$type}[$index]) { 8382 $ampel_count_button->{$type}[$index]->configure 8383 (-image => $ampel_klein_photo); 8384 updatekm(); 8385 } else { 8386 $ampel_count_button->{$type}[$index]->configure 8387 (-image => $ampel_klein_grey_photo); 8388 updatekm(); 8389 } 8390} 8391 8392sub change_kopfstein_count { 8393 my($type, $index) = @_; 8394 $kopfstein_count->{$type}[$index] = !$kopfstein_count->{$type}[$index]; 8395 if ($kopfstein_count->{$type}[$index]) { 8396 $kopfstein_count_button->{$type}[$index]->configure 8397 (-image => $kopfstein_klein_photo); 8398 updatekm(); 8399 } else { 8400 $kopfstein_count_button->{$type}[$index]->configure 8401 (-image => $kopfstein_klein_grey_photo); 8402 updatekm(); 8403 } 8404} 8405 8406# Erzeugt den String f�r den Label der Leistung 8407sub mk_power_txt { 8408 my($i) = @_; 8409 if (defined $i) { 8410 $power_txt[$i] = "$power[$i] W"; 8411 } else { 8412 for($i = 0; $i <= $#power; $i++) { 8413 $power_txt[$i] = "$power[$i] W"; 8414 } 8415 } 8416} 8417 8418# Dialog zum Eingeben der Leistung 8419### AutoLoad Sub 8420sub enter_power { 8421 my($i) = @_; 8422 my $t = redisplay_top($top, "power-$i", -title => M"Leistung"); 8423 return if !defined $t; 8424 my $var = $power[$i]; 8425 my $scale_var = $var; 8426 my $row = 0; 8427 $t->Label(-text => M('Leistung (in W)').':' 8428 )->grid(-row => $row, -column => 0); 8429 my $e = $t->Entry(-textvariable => \$var, 8430 -width => 4)->grid(-row => $row, -column => 1); 8431 $e->tabFocus; 8432 $row++; 8433 $t->Scale(-from => 10, 8434 -to => 500, 8435 -bigincrement => 50, 8436 -resolution => 5, 8437 -orient => 'horiz', 8438 -showvalue => 0, 8439 -variable => \$scale_var, 8440 -command => sub { $var = $scale_var }, 8441 )->grid(-row => $row, -column => 1, -sticky => 'we'); 8442 $row++; 8443 my $ref_row = $row; 8444 my $create_reference_label = sub { 8445 $t->Label(-text => M"Referenzleistung", 8446 )->grid(-row => $ref_row, -column => 0, -columnspan => 2); 8447 }; 8448 my $is_reference = ($active_speed_power{Type} eq 'power' && 8449 $active_speed_power{Index} eq $i); 8450 if (!$is_reference) { 8451 my $rb; 8452 $rb = $t->Button 8453 (-text => M"Als Referenzleistung verwenden", 8454 -command => sub { 8455 change_active_speed_power("power", $i); 8456 $create_reference_label->(); 8457 $rb->gridForget; 8458 }, 8459 )->grid(-row => $row, -column => 0, -columnspan => 2); 8460 $row++; 8461 } else { 8462 $create_reference_label->(); 8463 $row++; 8464 } 8465 my $close_window = sub { $t->destroy; }; 8466 my $apply_window = sub { IncBusy($t); 8467 eval { 8468 $power[$i] = $var; 8469 after_changed_power($i); 8470 }; 8471 DecBusy($t); 8472 }; 8473 my $ok_window = sub { &$close_window; 8474 &$apply_window }; 8475 my $bf = $t->Frame->grid(-row => $row, -column => 0, 8476 -columnspan => 2); 8477 my $okb = $bf->Button 8478 (Name => 'ok', 8479 -command => $ok_window)->grid(-row => 0, -column => 0, 8480 -sticky => 'ew'); 8481 $bf->Button(Name => 'apply', 8482 -command => $apply_window)->grid(-row => 0, -column => 1, 8483 -sticky => 'ew'); 8484 my $cb = $bf->Button 8485 (Name => 'close', 8486 -command => $close_window)->grid(-row => 0, -column => 2, 8487 -sticky => 'ew'); 8488 8489 $t->bind('<Return>' => sub { $okb->invoke }); 8490 $t->bind('<<CloseWin>>' => sub { $cb->invoke }); 8491 8492 my_popup($t); 8493} 8494 8495sub after_changed_power { 8496 my($i) = @_; # index 8497 my $is_reference = ($active_speed_power{Type} eq 'power' && 8498 $active_speed_power{Index} eq $i); 8499 mk_power_txt($i); 8500 calc_ampel_optimierung() 8501 if $ampel_optimierung && $is_reference; 8502 recalc_bikepwr(); 8503 updatekm(); 8504} 8505 8506sub get_reference_journey_time { 8507 my $key = $active_speed_power{Type} eq 'power' ? 'PowerTimeSeconds' : 'TimeSeconds'; 8508 $act_value{$key}->[$active_speed_power{Index}]; 8509} 8510 8511# Erzeugt den String f�r den Label der Geschwindigkeit 8512sub mk_speed_txt { 8513 my($i) = @_; 8514 if (defined $i) { 8515 $speed_txt[$i] = "$speed[$i] km/h"; 8516 } else { 8517 for($i = 0; $i <= $#speed; $i++) { 8518 $speed_txt[$i] = "$speed[$i] km/h"; 8519 } 8520 } 8521} 8522 8523# Dialog zum Eingeben der Geschwindigkeit 8524### AutoLoad Sub 8525sub enter_speed { 8526 my($i) = @_; 8527 my $t = redisplay_top($top, "speed-$i", -title => M"Geschwindigkeit"); 8528 return if !defined $t; 8529 my $var = $speed[$i]; 8530 my $scale_var = $var; 8531 my $row = 0; 8532 $t->Label(-text => M('Geschwindigkeit (in km/h)').':' 8533 )->grid(-row => $row, -column => 0); 8534 my $e = $t->Entry(-textvariable => \$var, 8535 -width => 3)->grid(-row => $row, -column => 1); 8536 $e->tabFocus; 8537 $row++; 8538 $t->Scale(-from => 5, 8539 -to => 60, 8540 -bigincrement => 5, 8541 -resolution => 1, 8542 -orient => 'horiz', 8543 -showvalue => 0, 8544 -variable => \$scale_var, 8545 -command => sub { $var = $scale_var }, 8546 )->grid(-row => $row, -column => 1, -sticky => 'we'); 8547 $row++; 8548 my $ref_row = $row; 8549 my $create_reference_label = sub { 8550 $t->Label(-text => M"Referenzgeschwindigkeit", 8551 )->grid(-row => $ref_row, -column => 0, -columnspan => 2); 8552 }; 8553 my $is_reference = ($active_speed_power{Type} eq 'speed' && 8554 $active_speed_power{Index} eq $i); 8555 if (!$is_reference) { 8556 my $rb; 8557 $rb = $t->Button 8558 (-text => M"Als Referenzgeschwindigkeit verwenden", 8559 -command => sub { 8560 change_active_speed_power("speed", $i); 8561 $create_reference_label->(); 8562 $rb->gridForget; 8563 }, 8564 )->grid(-row => $row, -column => 0, -columnspan => 2); 8565 $row++; 8566 } else { 8567 $create_reference_label->(); 8568 $row++; 8569 } 8570 my $close_window = sub { $t->destroy; }; 8571 my $apply_window = sub { IncBusy($t); 8572 eval { 8573 $speed[$i] = $var; 8574 mk_speed_txt($i); 8575 calc_ampel_optimierung() 8576 if $ampel_optimierung && $is_reference; 8577 updatekm(); 8578 }; 8579 DecBusy($t); 8580 }; 8581 my $ok_window = sub { &$close_window; 8582 &$apply_window }; 8583 my $bf = $t->Frame->grid(-row => $row, -column => 0, 8584 -columnspan => 2); 8585 my $okb = $bf->Button 8586 (Name => 'ok', 8587 -command => $ok_window)->grid(-row => 0, -column => 0, 8588 -sticky => 'ew'); 8589 $bf->Button(Name => 'apply', 8590 -command => $apply_window)->grid(-row => 0, -column => 1, 8591 -sticky => 'ew'); 8592 my $cb = $bf->Button 8593 (Name => 'close', 8594 -command => $close_window)->grid(-row => 0, -column => 2, 8595 -sticky => 'ew'); 8596 $t->bind('<Return>' => sub { $okb->invoke }); 8597 $t->bind('<<CloseWin>>' => sub { $cb->invoke }); 8598 8599 my_popup($t); 8600} 8601 8602# Dialog zum Eingeben der Windgeschwindigkeit und -richtung 8603### AutoLoad Sub 8604sub enter_wind { 8605 require Tk::Optionmenu; 8606 require Met::Wind; 8607 import Met::Wind; 8608 my $t = redisplay_top($top, "wind", -title => M"Wind"); 8609 return if !defined $t; 8610 my @var = ($winddir, $wind_v_max, $wind_v); 8611 my @scale_var = @var; 8612 my(@e, @om, @sc); 8613 my %wind_range = 8614 ('Beaufort' => [0, 16], 8615 'm/s' => [0, 56], 8616 'km/h' => [0, 200], 8617 'mi/h' => [0, 125], 8618 'kn' => [0, 100]); 8619 my @wind_unit = (undef, 'm/s', 'm/s'); 8620 my @last_wind_unit = @wind_unit; 8621 $t->Label(-text => M("Windrichtung").":")->grid(-row => 0, -column => 0); 8622 $t->Label(-text => M("max. Windgeschwindigkeit").":" 8623 )->grid(-row => 1, -column => 0); 8624 $t->Label(-text => M("mitt. Windgeschwindigkeit").":" 8625 )->grid(-row => 2, -column => 0); 8626 8627 my $rbf = $t->Frame->grid(-row => 0, -column => 1, -columnspan => 10); 8628 foreach my $spec ([qw(sw 0 2)], 8629 [qw(w 0 1)], 8630 [qw(nw 0 0)], 8631 [qw(n 1 0)], 8632 [qw(ne 2 0)], 8633 [qw(e 2 1)], 8634 [qw(se 2 2)], 8635 [qw(s 1 2)]) { 8636 my($windri, $col, $row) = @$spec; 8637 $col*=2; 8638 $rbf->Label(-text => uc($windri))->grid(-row => $row, 8639 -column => $col); 8640 $rbf->Radiobutton(-variable => \$var[0], -value => $windri, 8641 )->grid(-row => $row, -column => $col+1); 8642 } 8643 if (defined $windrose2_photo) { 8644 $rbf->Label(-image => $windrose2_photo)->grid(-row => 1, 8645 -column => 1*2, 8646 -columnspan => 2); 8647 } 8648 8649 for(my $i = 1; $i <= $#var; $i++) { 8650 $e[$i] = $t->Entry(-textvariable => \$var[$i], 8651 -width => 5)->grid(-row => $i, -column => 1); 8652 } 8653 8654 for(my $i = 1; $i <= $#var; $i++) { 8655 my $ii = $i; 8656 $om[$i] = $t->Optionmenu 8657 (-takefocus => 1, 8658 -highlightthickness => 2, 8659 -variable => \$wind_unit[$i], 8660 -command => sub { 8661 if ($last_wind_unit[$ii] ne $wind_unit[$ii]) { 8662 my $old_var = $var[$ii]; 8663 $sc[$ii]->configure 8664 (-from => $wind_range{$wind_unit[$ii]}->[0], 8665 -to => $wind_range{$wind_unit[$ii]}->[1], 8666 ); 8667 $var[$ii] = wind_velocity([$old_var, 8668 $last_wind_unit[$ii]], 8669 $wind_unit[$ii]); 8670 $last_wind_unit[$ii] = $wind_unit[$ii]; 8671 } 8672 })->grid(-row => $i, -column => 2); 8673 $om[$i]->addOptions('m/s', 'km/h', 'Beaufort', 'mi/h', 'kn'); 8674 $sc[$i] = $t->Scale(-from => $wind_range{$wind_unit[$i]}->[0], 8675 -to => $wind_range{$wind_unit[$i]}->[1], 8676 -orient => 'horiz', 8677 -showvalue => 0, 8678 -variable => \$scale_var[$i], 8679 -command => sub { $var[$ii] = $scale_var[$ii] }, 8680 )->grid(-row => $i, -column => 3, -sticky => 'we'); 8681 } 8682 8683 $rbf->focus; 8684 for(my $i = 1; $i < $#var; $i++) { 8685 my $ii = $i; 8686 $e[$i]->bind('<Return>' => sub { $e[$ii+1]->tabFocus }); 8687 } 8688 8689 my $apply_window = sub { 8690 for(my $i = 1; $i <= $#var; $i++) { 8691 if ($wind_unit[$i] ne 'm/s') { 8692 $om[$i]->setOption('m/s'); 8693 # Der Rest wird automatisch im -command vom Optionmenu 8694 # erledigt. 8695 } 8696 } 8697 if (defined $var[0] and $var[0] =~ /^([ns][ew]?|[ew])$/i) { 8698 analyze_wind(undef, undef, @var); 8699 $wind = 1; # XXX ? 8700 if ($coloring eq 'wind') { 8701 redraw_path(); 8702 updatekm(); 8703 } 8704 } else { 8705 status_message(Mfmt("Unerlaubte Windrichtung: <%s>", $var[0]), 8706 'warn'); 8707 } 8708 }; 8709 my $close_window = sub { $t->destroy }; 8710 my $ok_window = sub { &$close_window; 8711 &$apply_window; }; 8712 8713 my $bf = $t->Frame->grid(-row => 3, -column => 0, 8714 -columnspan => 10, -sticky => 'we'); 8715 my $okb = $bf->Button(Name => 'ok', 8716 -command => $ok_window, 8717 )->pack(-side => 'left', -fill => 'x', -expand => 1); 8718 $bf->Button(Name => 'apply', 8719 -command => $apply_window, 8720 )->pack(-side => 'left', -fill => 'x', -expand => 1); 8721 my $cb = $bf->Button(Name => 'close', 8722 -command => $close_window, 8723 )->pack(-side => 'left', -fill => 'x', -expand => 1); 8724 $bf->Label->pack(-side => 'left', -fill => 'x', -expand => 1); 8725 $bf->Button(-text => M"Beaufort-Tabelle", 8726 -command => sub { 8727 Met::Wind::beaufort_table 8728 ($t, 8729 -command => sub { 8730 my($num, $unit, $toplevel) = @_; 8731 $var[2] = Met::Wind::wind_velocity([$num, $unit], 8732 $wind_unit[2]); 8733 $toplevel->destroy; 8734 }, 8735 ) 8736 }, 8737 )->pack(-side => 'left', -fill => 'x', -expand => 1); 8738 8739 $e[-1]->bind('<Return>' => sub { $okb->invoke }); 8740 $t->bind('<<CloseWin>>' => sub { $cb->invoke }); 8741 my_popup($t); 8742} 8743 8744# Dialog zum Eingeben des Mapscales 8745### AutoLoad Sub 8746sub enter_scale { 8747 my(%args) = @_; 8748 my($x,$y) = @{ $args{-preserveposition} || [] }; 8749 return unless $mapscale =~ /:\s*(\d+)/; 8750 my($old_mapscale, $new_mapscale, $new_mapscale_scale); 8751 $old_mapscale = $new_mapscale = $new_mapscale_scale = $1; 8752 8753 my $t = redisplay_top($top, "scale", -title => M"Ma�stab"); 8754 return if !defined $t; 8755 $t->Label(-text => M"Ma�stab 1:" 8756 )->grid(-row => 0, -column => 0, -sticky => 'e'); 8757 my $e = $t->Entry(-textvariable => \$new_mapscale, 8758 -width => 8)->grid(-row => 0, -column => 1, 8759 -sticky => 'ew'); 8760 $e->tabFocus; 8761 my $sc; 8762 if (defined $default_mapscale && $default_mapscale != 0) { 8763 $t->Button(Name => 'default', 8764 -command => sub { 8765 $new_mapscale = $new_mapscale_scale = $default_mapscale; 8766 }, 8767 )->grid(-row => 0, -column => 2); 8768 } 8769 my $Scale = 'Scale'; 8770 my %scaleargs = (-bigincrement => 5000, 8771 -resolution => 1000, 8772 -showvalue => 0, 8773 ); 8774 eval { 8775 require Tk::LogScale; 8776 require Tie::Watch; 8777 $Scale = 'LogScale'; 8778 %scaleargs = (-resolution => 0.01, 8779 -showvalue => 0); 8780 }; 8781 my $scale = $t->$Scale 8782 (-from => 1000, 8783 -to => 3_000_000, 8784 %scaleargs, 8785 -orient => 'horiz', 8786 -variable => \$new_mapscale_scale, 8787 -command => sub { $new_mapscale = int($new_mapscale_scale); }, 8788 )->grid(-row => 1, -column => 1, 8789 -columnspan => 2, 8790 -sticky => 'we'); 8791 my $close_window = sub { $t->destroy; }; 8792 my $apply_window = sub { 8793 IncBusy($t); 8794 eval { 8795 if ($old_mapscale != $new_mapscale and $new_mapscale != 0) { 8796 scalecanvas($c, $old_mapscale/$new_mapscale, $x, $y); 8797 if ($mapscale =~ /:\s*(\d+)/) { 8798 $old_mapscale = $new_mapscale = $1; 8799 if (Tk::Exists($scale)) { 8800 # Die Abfrage ist ein Workaround, ansonsten 8801 # gibt es einen Perl-Panic, wenn Tk::LogScale 8802 # verwendet wird. M�glicher Grund: es wird auf 8803 # eine Tie-Variable zugegriffen, die 8804 # anscheinend schon zerst�rt ist (?), bzw. 8805 # deren Tie-Objekt zerst�rt ist. 8806 $new_mapscale_scale = $1; 8807 } 8808 } else { 8809 die Mfmt("Fehler beim Parsen des Massstabs: %s", 8810 $mapscale); 8811 } 8812 } 8813 }; 8814 DecBusy($t); 8815 }; 8816 my $ok_window = sub { &$close_window; 8817 &$apply_window }; 8818 my $bf = $t->Frame->grid(-row => 2, -column => 0, 8819 -columnspan => 2); 8820 my $okb = $bf->Button 8821 (Name => 'ok', 8822 -command => $ok_window)->grid(-row => 0, -column => 0, 8823 -sticky => 'ew'); 8824 $bf->Button(Name => 'apply', 8825 -command => $apply_window)->grid(-row => 0, -column => 1, 8826 -sticky => 'ew'); 8827 my $cb = $bf->Button 8828 (Name => 'close', 8829 -command => $close_window)->grid(-row => 0, -column => 2, 8830 -sticky => 'ew'); 8831 8832 $t->bind('<Return>' => sub { $okb->invoke }); 8833 $t->bind('<<CloseWin>>' => sub { $cb->invoke }); 8834 8835 my_popup($t); 8836} 8837 8838# �ndert den -state einer gesamten Widgethierarchie unter $frame 8839# $enable gibt an, ob die Widgets de/aktiviert werden sollen 8840# $exceptions ist ein Hash, wobei die Keys die Ausnahmen unter den Widgets 8841# angeben 8842### AutoLoad Sub 8843sub change_state_all { 8844 my($frame, $enable, $exceptions) = @_; 8845 foreach ($frame->children) { 8846 next if exists $exceptions->{$_}; 8847 if ($enable) { 8848 eval { $_->configure(-state => 'normal') }; 8849 } else { 8850 eval { $_->configure(-state => 'disabled') }; 8851 } 8852 if ($_->can('children')) { 8853 change_state_all($_, $enable, $exceptions); 8854 } 8855 } 8856} 8857 8858sub toggle_enter_opt_preferences { 8859 if ($show_enter_opt_preferences) { 8860 enter_opt_preferences(); 8861 } else { 8862 $toplevel{"optparam"}->withdraw 8863 if Tk::Exists($toplevel{"optparam"}); 8864 } 8865} 8866 8867# Dialog zum Einstellen der Optimierungseinstellungen 8868### AutoLoad Sub 8869sub enter_opt_preferences { 8870 my($i) = @_; 8871 $show_enter_opt_preferences = 1; 8872 my $t = redisplay_top($top, "optparam", -title => M"Optimierungsparameter"); 8873 return if !defined $t; 8874 my $withdraw = sub { $show_enter_opt_preferences = 0; 8875 $t->withdraw; 8876 }; 8877 $t->protocol('WM_DELETE_WINDOW', $withdraw); 8878 require Tk::NoteBook; 8879 my $nb = $t->NoteBook->grid(-row => 0, -column => 0, 8880 -columnspan => 3); 8881 my %var = %qualitaet_s_speed; 8882 my %var4 = %handicap_s_speed; 8883 my %var2 = %strcat_speed; 8884 my %var3 = %radwege_speed; 8885 my $Entry = 'Entry'; 8886 my @EntryArgs = (); 8887 eval { 8888 require Tk::NumEntry; 8889 $Entry = 'NumEntry'; 8890 @EntryArgs = (-minvalue => 1); 8891 }; 8892 my @act_page; 8893 $act_page[0] = $nb->add("q", -label => M"Stra�enqualit�t"); 8894 my $gridy = 0; 8895 $act_page[0]->Label(-text => M"Stra�enqualit�t", 8896 -font => $font{'bold'})->grid(-row => $gridy, 8897 -column => 0); 8898 $act_page[0]->Label(-text => M"max. Geschwindigkeit", 8899 -font => $font{'bold'})->grid(-row => $gridy, 8900 -column => 1, 8901 -columnspan => 2, 8902 ); 8903 $gridy++; 8904#XXX geht nicht...warum ??? 8905# $t->bind('<Return>' => sub { 8906# warn $t->focusCurrent; 8907# if ($t->focusCurrent->isa('Tk::Entry')) { 8908# $t->focusNext->tabFocus; 8909# } 8910# }); 8911 8912 my @e; 8913 for (0 .. 3) { 8914 my $i = $_; 8915 $act_page[0]->Label(-text => "Q$i: " . 8916 $category_attrib{"Q$i"}->[ATTRIB_LONG], 8917 )->grid(-row => $gridy, -column => 0, -sticky => 'w'); 8918 my $w; 8919 $w = $e[$i] = $act_page[0]->$Entry(-textvariable => \$var{"Q$i"}, 8920 -width => 3, 8921 @EntryArgs, 8922 ); 8923 $w->grid(-row => $gridy, -column => 1, -sticky => 'e'); 8924 $act_page[0]->Label(-text => 'km/h')->grid(-row => $gridy, -column => 2, 8925 -sticky => 'w'); 8926 $gridy++; 8927 } 8928 $e[0]->tabFocus; 8929 8930 { 8931 require Tk::Optionmenu; 8932 my $name2inx = 8933 {M"egal" => 0, 8934 M"Kopfsteinpflaster und schlechte Fahrbahnen vermeiden" => 1, 8935 M"nur sehr gute Bel�ge bevorzugen (rennradtauglich)" => 2, 8936 M"freie Eingabe" => 3, 8937 }; 8938 my $default = M"freie Eingabe"; 8939 my $o = $act_page[0]->Optionmenu 8940 (-options => [sort { $name2inx->{$a} <=> $name2inx->{$b} } keys %$name2inx], 8941 -variable => \$default, 8942 -command => sub { 8943 my $inx = $name2inx->{$default}; 8944 my $speed = get_active_speed(); 8945 if ($inx == 0) { 8946 while(my($k,$v) = each %var) { 8947 $var{$k} = $speed; 8948 } 8949 } elsif ($inx == 3) { 8950 # no op 8951 } else { 8952 my $velocity_kmh = $speed; 8953 # Taken from bbbike.cgi 8954 my %penalty; 8955 my %max_limit; 8956 if ($inx == 2) { # rennradtauglich 8957 %penalty = ( "Q0" => 1, 8958 "Q1" => 1.2, 8959 "Q2" => 1.6, 8960 "Q3" => 2 ); 8961 %max_limit = ( Q1 => $velocity_kmh / 25, 8962 Q2 => $velocity_kmh / 16, 8963 Q3 => $velocity_kmh / 10 ); 8964 } else { 8965 %penalty = ( "Q0" => 1, 8966 "Q1" => 1, 8967 "Q2" => 1.5, 8968 "Q3" => 1.8 ); 8969 %max_limit = ( Q1 => $velocity_kmh / 25, 8970 Q2 => $velocity_kmh / 18, 8971 Q3 => $velocity_kmh / 13 ); 8972 } 8973 my $min_limit = $velocity_kmh / 5; 8974 for my $q (keys %max_limit) { 8975 if ($penalty{$q} < $max_limit{$q}) { 8976 $penalty{$q} = $max_limit{$q}; 8977 } 8978 } 8979 if ($velocity_kmh > 5) { 8980 for my $q (keys %penalty) { 8981 if ($penalty{$q} > $min_limit) { 8982 $penalty{$q} = $min_limit; 8983 } 8984 } 8985 } 8986 8987 while(my($k,$v) = each %penalty) { 8988 $var{$k} = int($speed/$v); 8989 } 8990 } 8991 } 8992 )->grid(-row => $gridy, 8993 -column => 0, 8994 -sticky => 'w'); 8995 } 8996 8997 my $cb1; 8998 $cb1 = $act_page[0]->Checkbutton 8999 (-text => M"Verwenden", 9000 -variable => \$qualitaet_s_optimierung, 9001 -command => sub { change_state_all($act_page[0], $qualitaet_s_optimierung, 9002 {$cb1=>1}); }, 9003 )->grid(-row => $gridy++, 9004 -column => 2, 9005 -sticky => 'e'); 9006 change_state_all($act_page[0], $qualitaet_s_optimierung, {$cb1=>1}); 9007 9008 ####### 9009 $act_page[1] = $nb->add("cat", -label => M"Stra�enkategorien", 9010-createcmd => sub { 9011 $gridy = 0; 9012 $act_page[1]->Label(-text => M"Stra�enkategorien", 9013 -font => $font{'bold'})->grid(-row => $gridy, 9014 -column => 0); 9015 $act_page[1]->Label(-text => M"max. Geschwindigkeit", 9016 -font => $font{'bold'})->grid(-row => $gridy, 9017 -column => 1, 9018 -columnspan => 2, 9019 ); 9020 $gridy++; 9021 # XXX no BAB here! 9022 for (qw(HH H NH N NN)) { 9023 my $i = $_; 9024 next if $_ eq 'NH' && !$city_obj->is_osm_source && !$devel_host; # XXX maybe only restrict in edit mode??? 9025 $act_page[1]->Label(-text => $category_attrib{$i}->[ATTRIB_PLURAL] . ": " 9026 )->grid(-row => $gridy, -column => 0, 9027 -sticky => 'w'); 9028 my $w = $act_page[1]->$Entry(-textvariable => \$var2{$i}, 9029 -width => 3, 9030 @EntryArgs, 9031 ); 9032 # bind return XXX 9033 $w->grid(-row => $gridy, -column => 1, -sticky => 'e'); 9034 $act_page[1]->Label(-text => 'km/h')->grid(-row => $gridy, -column => 2, 9035 -sticky => 'w'); 9036 $gridy++; 9037 } 9038 9039 { 9040 require Tk::Optionmenu; 9041 # Die Verwendung von $name2inx ist nur ein Workaround... 9042 # Eigentlich w�rde ich die [Name => Wert]-Notation von Optionmenu 9043 # verwenden wollen, aber das geht nicht :-( 9044 my $name2inx = 9045 {M"Nur Hauptstra�en" => 0, 9046 M"Hauptstra�en bevorzugen" => 1, 9047 M"Alle Stra�en ber�cksichtigen" => 2, 9048 M"Nebenstra�en bevorzugen" => 3, 9049 M"Nur Nebenstra�en" => 4, 9050 }; 9051 my $default = M"Alle Stra�en ber�cksichtigen"; 9052 my $o = $act_page[1]->Optionmenu 9053 (-options => [sort { $name2inx->{$a} <=> $name2inx->{$b} } keys %$name2inx], 9054 -variable => \$default, 9055 -command => sub { 9056 my $i = 0; 9057 # XXX BAB 9058 # XXX should be relative to current speed, like in cgi! 9059 # XXX rethink penalty for NH, maybe like in cgi! 9060 for (qw(HH H NH N NN)) { 9061 $var2{$_} = [[100,100,100,1,1], 9062 [100,100,100,12,12], 9063 [100,100,100,100,100], 9064 [12,12,100,100,100], 9065 [1,1,100,100,100], 9066 ]->[$name2inx->{$default}][$i]; 9067 $i++; 9068 } 9069 })->grid(-row => $gridy, 9070 -column => 0, 9071 -sticky => 'w'); 9072 } 9073 9074 my $cb2; 9075 $cb2 = $act_page[1]->Checkbutton 9076 (-text => M"Verwenden", 9077 -variable => \$strcat_optimierung, 9078 -command => sub { change_state_all($act_page[1], $strcat_optimierung, 9079 {$cb2=>2}); }, 9080 )->grid(-row => $gridy++, 9081 -column => 2, 9082 -sticky => 'e'); 9083 change_state_all($act_page[1], $strcat_optimierung, {$cb2=>2}); 9084}); 9085 ####### 9086 $act_page[2] = $nb->add("rw", -label => M"Radwege", 9087-createcmd => sub { 9088 $gridy = 0; 9089 $act_page[2]->Label(-text => M"Radwege", 9090 -font => $font{'bold'})->grid(-row => $gridy, 9091 -column => 0); 9092 $act_page[2]->Label(-text => M"max. Geschwindigkeit", 9093 -font => $font{'bold'})->grid(-row => $gridy, 9094 -column => 1, 9095 -columnspan => 2, 9096 ); 9097 $gridy++; 9098 require Radwege; 9099 for (@Radwege::bbbike_category_order) { 9100 my $i = $_; 9101 $act_page[2]->Label(-text => $Radwege::bez{$i} .": " 9102 )->grid(-row => $gridy, -column => 0, 9103 -sticky => 'w'); 9104 my $w = $act_page[2]->$Entry(-textvariable => \$var3{$i}, 9105 -width => 3, 9106 @EntryArgs, 9107 ); 9108 # bind return XXX 9109 $w->grid(-row => $gridy, -column => 1, -sticky => 'e'); 9110 $act_page[2]->Label(-text => 'km/h')->grid(-row => $gridy, -column => 2, 9111 -sticky => 'w'); 9112 $gridy++; 9113 } 9114 9115 my $N_RW_cb; 9116 my $N_RW1_cb; 9117 my $cb3; 9118 $cb3 = $act_page[2]->Checkbutton 9119 (-text => M"Verwenden", 9120 -variable => \$radwege_optimierung, 9121 -command => sub { change_state_all($act_page[2], $radwege_optimierung, 9122 {$cb3=>1,$N_RW_cb=>1,$N_RW1_cb=>1}); }, 9123 )->grid(-row => $gridy++, 9124 -column => 2, 9125 -sticky => 'e'); 9126 change_state_all($act_page[2], $radwege_optimierung, {$cb3=>3}); 9127 9128 $N_RW_cb = $act_page[2]->Checkbutton 9129 (-text => M"Hauptstra�en ohne Radwege/Busspuren meiden", 9130 -variable => \$N_RW_optimization, 9131 -command => sub { 9132 if ($N_RW_optimization) { 9133 $radwege_optimierung = 0; 9134 $strcat_optimierung = 0; 9135 $N_RW1_optimization = 0; 9136 change_state_all($act_page[2], $radwege_optimierung, 9137 {$cb3=>1,$N_RW_cb=>1,$N_RW1_cb=>1}); 9138 } 9139 }, 9140 )->grid(-row => $gridy++, 9141 -column => 0, 9142 -sticky => "w"); 9143 $N_RW1_cb = $act_page[2]->Checkbutton 9144 (-text => M"Hauptstra�en ohne Radwege meiden", 9145 -variable => \$N_RW1_optimization, 9146 -command => sub { 9147 if ($N_RW1_optimization) { 9148 $radwege_optimierung = 0; 9149 $strcat_optimierung = 0; 9150 $N_RW_optimization = 0; 9151 change_state_all($act_page[2], $radwege_optimierung, 9152 {$cb3=>1,$N_RW_cb=>1,$N_RW1_cb=>1}); 9153 } 9154 }, 9155 )->grid(-row => $gridy++, 9156 -column => 0, 9157 -sticky => "w"); 9158}); 9159 9160 ####### 9161 $act_page[3] = $nb->add("lsa", -label => M"Ampel-Optimierung", 9162-createcmd => sub { 9163 $gridy = 0; 9164 $act_page[3]->Label(-text => M"Ampel-Optimierung", 9165 -font => $font{'bold'})->grid(-row => $gridy, 9166 -column => 0); 9167# $act_page[3]->Label(-text => M"max. Geschwindigkeit", 9168# -font => $font{'bold'})->grid(-row => $gridy, 9169# -column => 1, 9170# -columnspan => 2, 9171# ); 9172 $gridy++; 9173 9174 my $dgf = $act_page[3]->Frame->grid(-row => $gridy++, -column => 0, 9175 -sticky => 'w', -columnspan => 3); 9176 my $gridyy = 0; 9177 $dgf->Label(-text => M("Durchschnittsgeschwindigkeit (km/h)").":" 9178 )->grid(-row => $gridyy, -column => 0, 9179 -sticky => 'w'); 9180 my $gridxx = 1; 9181 for (qw(10 15 20 25 30)) { 9182 $dgf->Radiobutton(-text => $_, 9183 -variable => \$average_v, 9184 -value => $_, 9185 -command => \&calc_ampel_optimierung, 9186 )->grid(-row => $gridyy, -column => $gridxx++, 9187 -sticky => 'w'); 9188 } 9189 $gridyy++; 9190 my $am_frame = $dgf->Frame->grid(-row => $gridyy, 9191 -column => 1, 9192 -columnspan => 5, 9193 -sticky => "nw"); 9194 $am_frame->Radiobutton(-text => M"Automatisch", 9195 -variable => \$average_v, 9196 -value => 0, 9197 -command => \&calc_ampel_optimierung, 9198 )->pack(-side => 'left'); 9199 $am_frame->Radiobutton(-text => M"Manuell �ber Strecke", 9200 -variable => \$average_v, 9201 -value => -1, 9202 -command => \&calc_ampel_optimierung, 9203 )->pack(-side => 'left'); 9204 9205 $dgf->Label(-text => M("Beschleunigung (m/s^2)").":" 9206 )->grid(-row => ++$gridyy, -column => 0, 9207 -sticky => 'w'); 9208 $gridxx = 1; 9209 my $found_beschleunigung; 9210 for (qw(0.5 1 1.5 2)) { 9211 $dgf->Radiobutton(-text => $_, 9212 -variable => \$beschleunigung, 9213 -value => $_, 9214 -command => \&calc_ampel_optimierung, 9215 )->grid(-row => $gridyy, -column => $gridxx++, 9216 -sticky => 'w'); 9217 if ($beschleunigung == $_) { 9218 $found_beschleunigung++; 9219 } 9220 } 9221 9222 if (!$beschleunigung) { $beschleunigung = 1 } 9223 if (!$found_beschleunigung) { 9224 if ($beschleunigung > 2) { $beschleunigung = 2 } 9225 elsif ($beschleunigung < 0.5) { $beschleunigung = 0.5 } 9226 $beschleunigung = int($beschleunigung*2)/2; 9227 } 9228 $gridyy++; 9229 9230 $dgf->Label(-text => M("Verlorene Strecke (m)").":" 9231 )->grid(-row => $gridyy, -column => 0, -sticky => "w"); 9232 $dgf->Entry(-textvariable => \$lost_strecke_per_ampel, 9233 -width => 5 9234 )->grid(-row => $gridyy, -column => 1, 9235 -columnspan => 5, -sticky => "w"); 9236 9237 my $cb4; 9238 $cb4 = $act_page[3]->Checkbutton 9239 (-text => M"Verwenden", 9240 -variable => \$ampel_optimierung, 9241 -command => sub { change_state_all($act_page[3], $ampel_optimierung, 9242 {$cb4=>4}); }, 9243 )->grid(-row => $gridy++, 9244 -column => 2, 9245 -sticky => 'e'); 9246 change_state_all($act_page[3], $ampel_optimierung, {$cb4=>4}); 9247}); 9248 9249 #### 9250 $act_page[4] = $nb->add("h", -label => M"Sonst. Beeintr�chtigungen"); 9251 $gridy = 0; 9252 $act_page[4]->Label(-text => M"Sonst. Beeintr�chtigungen", 9253 -font => $font{'bold'})->grid(-row => $gridy, 9254 -column => 0); 9255 $act_page[4]->Label(-text => M"max. Geschwindigkeit", 9256 -font => $font{'bold'})->grid(-row => $gridy, 9257 -column => 1, 9258 -columnspan => 2, 9259 ); 9260 $gridy++; 9261#XXX geht nicht...warum ??? 9262# $t->bind('<Return>' => sub { 9263# warn $t->focusCurrent; 9264# if ($t->focusCurrent->isa('Tk::Entry')) { 9265# $t->focusNext->tabFocus; 9266# } 9267# }); 9268 9269 @e = (); 9270 for (0 .. 4) { 9271 my $i = $_; 9272 $act_page[4]->Label(-text => "q$i: " . 9273 $category_attrib{"q$i"}->[ATTRIB_LONG], 9274 )->grid(-row => $gridy, -column => 0, -sticky => 'w'); 9275 my $w; 9276 $w = $e[$i] = $act_page[4]->$Entry(-textvariable => \$var4{"q$i"}, 9277 -width => 3, 9278 @EntryArgs, 9279 ); 9280 $w->grid(-row => $gridy, -column => 1, -sticky => 'e'); 9281 $act_page[4]->Label(-text => 'km/h')->grid(-row => $gridy, -column => 2, 9282 -sticky => 'w'); 9283 $gridy++; 9284 } 9285 $e[0]->tabFocus; 9286 9287 my $cb5; 9288 $cb5 = $act_page[4]->Checkbutton 9289 (-text => M"Verwenden", 9290 -variable => \$handicap_s_optimierung, 9291 -command => sub { change_state_all($act_page[4], $handicap_s_optimierung, 9292 {$cb5=>5}); }, 9293 )->grid(-row => $gridy++, 9294 -column => 2, 9295 -sticky => 'e'); 9296 change_state_all($act_page[4], $handicap_s_optimierung, {$cb5=>5}); 9297 9298 ####### 9299 $gridy = 1; 9300#XXX my $close_window = sub { $t->destroy; }; 9301 my $close_window = $withdraw; 9302 my $apply_window = sub { eval { 9303 while(my($k,$v) = each %var) { 9304 if ($qualitaet_s_speed{$k} != $v) { 9305 undef $qualitaet_s_net; 9306 } 9307 $qualitaet_s_speed{$k} = $v; 9308 } 9309 while(my($k,$v) = each %var2) { 9310 if ($strcat_speed{$k} != $v) { 9311 undef $strcat_net; 9312 } 9313 $strcat_speed{$k} = $v; 9314 } 9315 # special: B == HH 9316 $strcat_speed{"B"} = $strcat_speed{"HH"}; 9317 while(my($k,$v) = each %var3) { 9318 if ($radwege_speed{$k} != $v) { 9319 undef $radwege_net; 9320 } 9321 $radwege_speed{$k} = $v; 9322 } 9323 while(my($k,$v) = each %var4) { 9324 if ($handicap_s_speed{$k} != $v) { 9325 undef $handicap_s_net; 9326 } 9327 $handicap_s_speed{$k} = $v; 9328 } 9329 }; 9330 }; 9331 my $ok_window = sub { &$close_window; 9332 &$apply_window }; 9333 my $bf = $t->Frame->grid(-row => $gridy++, -column => 0, 9334 -columnspan => 3); 9335 my $okb = $bf->Button 9336 (Name => 'ok', 9337 -command => $ok_window)->grid(-row => 0, -column => 0, 9338 -sticky => 'ew'); 9339 $bf->Button(Name => 'apply', 9340 -command => $apply_window)->grid(-row => 0, -column => 1, 9341 -sticky => 'ew'); 9342 my $clb = $bf->Button 9343 (Name => 'close', 9344 -command => $close_window)->grid(-row => 0, -column => 2, 9345 -sticky => 'ew'); 9346 9347 $t->bind('<Return>' => sub { $okb->invoke }); 9348 $t->bind('<<CloseWin>>' => sub { $clb->invoke }); 9349 9350 $t->Popup(@popup_style); 9351} 9352 9353# Macht aus den negativen Werten positive und aus den positiven reziproke 9354# Werte f�r die Penalty-Berechnung. 9355### AutoLoad Sub 9356sub optprefs2penalty { 9357 my $val = shift; 9358 if ($val < 0 ) { 9359 $val = -$val; 9360 } elsif ($val > 0) { 9361 $val = 1/$val; 9362 } 9363} 9364 9365# Alternativer Dialog zum Einstellen der Optimierung. Noch nicht 9366# fertig. 9367### AutoLoad Sub 9368sub enter_opt_preferences2 { 9369 my $t = redisplay_top($top, "optprefs", -title => M"Optimierungsvorlieben"); 9370#XXX handicap XXX 9371 return if !defined $t; 9372 my @l = ([M"Ampeln", M"Ampeln vermeiden", M"Ampeln bevorzugen"], 9373 [M"Abbiegen", M"Abbiegen vermeiden", M"Abbiegen bevorzugen"], 9374 [M"Qualit�t", M"schlechte Qualit�t vermeiden", M"schlechte Qualit�t bevorzugen"], 9375 [M"Kategorie", M"Hauptstra�en vermeiden", M"Nebenstra�en vermeiden"], 9376 [M"Radwege", M"Radwege vermeiden", M"Radwege bevorzugen"], 9377 [M"Steigung", M"Steigungen vermeiden", M"Steigungen bevorzugen"]); 9378 9379# Kategorie: B/HH: 3, H: 2, NH/N: 1, NN: 0 9380 9381# Kat Scale Res 9382 9383# 0 -5 -5 9384# 1 -5 -2 9385# 2 -5 +2 9386# 3 -5 +5 9387 9388# 0 -3 -3 9389# 1 -3 -1 9390# 2 -3 +1 9391# 3 -3 +3 9392 9393# 0 0 0 9394# 1 0 0 9395# 2 0 0 9396# 3 0 0 9397 9398# 0 +3 +3 9399# 1 +3 +1 9400# 2 +3 -1 9401# 3 +3 -3 9402 9403# 0 +5 +5 9404# 1 +5 +2 9405# 2 +5 -2 9406# 3 +5 -5 9407 9408 my @scale; 9409 my $y = 0; 9410 for my $l_def (@l) { 9411 my($l, $minus, $plus) = @$l_def; 9412 $optprefs{$l} = 0 unless defined $optprefs{$l}; 9413 $t->Label(-text => $minus)->grid(-row => $y, -column => 0, 9414 -sticky => 'e', 9415 ); 9416 $scale[$y] = $t->Scale(-showvalue => 0, 9417 -from => -5, 9418 -to => 5, 9419 -variable => \$optprefs{$l}, 9420 -orient => 'h')->grid(-row => $y, -column => 1); 9421 $t->Label(-text => $plus)->grid(-row => $y, -column => 2, 9422 -sticky => 'w', 9423 ); 9424 $y++; 9425 } 9426 9427 my $close_window = sub { $t->destroy; }; 9428 # XXX �berhaupt mit apply und so arbeiten? Wie war das gedacht gewesen? 9429 my $apply_window = sub { 9430 eval { 9431 # Ampeloptimierung 9432 #XXX $lost_time_per_ampel = -$optprefs{"Ampeln"}*?; 9433 # XXX what about F ...? 9434 $lost_strecke_per_ampel = -$optprefs{"Ampeln"}*40; 9435 $ampel_optimierung = ($optprefs{Ampeln} != 0); 9436 9437 # Abbiegeoptimierung 9438 $abbiege_penalty = -$optprefs{"Abbiegen"}*30; 9439 $abbiege_optimierung = ($optprefs{Abbiegen} != 0); 9440 9441 # Qualit�tsoptimierung 9442# foreach (0 .. 3) { 9443# $qualitaet_s_speed{"Q 9444# $qualitaet_s_optimierung = ($optprefs{Qualit�t} != 0); 9445 }; 9446 }; 9447 my $ok_window = sub { &$close_window; 9448 &$apply_window }; 9449 my $bf = $t->Frame->grid(-row => $y++, -column => 0, 9450 -columnspan => 3, 9451 -sticky => "ew"); 9452 my $gridx = 0; 9453 my $okb = $bf->Button 9454 (Name => 'ok', 9455 -command => $ok_window)->grid(-row => 0, -column => $gridx++, 9456 -sticky => 'ew'); 9457 $bf->Button(-text => M"Zur�cksetzen", 9458 -command => sub { 9459 for my $l_def (@l) { 9460 $optprefs{$l_def->[0]} = 0; 9461 } 9462 })->grid(-row => 0, 9463 -column => $gridx++, 9464 -sticky => 'ew'); 9465 $bf->Button(Name => 'apply', 9466 -command => $apply_window)->grid(-row => 0, 9467 -column => $gridx++, 9468 -sticky => 'ew'); 9469 my $clb = $bf->Button 9470 (Name => 'close', 9471 -command => $close_window)->grid(-row => 0, -column => $gridx++, 9472 -sticky => 'ew'); 9473 9474 $t->bind('<Return>' => sub { $okb->invoke }); 9475 $t->bind('<<CloseWin>>' => sub { $clb->invoke }); 9476 9477 $t->idletasks; 9478 my $bar = $t->Frame(-bg => 'red' 9479 )->place('-y' => $scale[0]->y, 9480 '-x' => $scale[0]->x + $scale[0]->width/2-1, 9481 -width => 2, 9482 -height => ($scale[-1]->y-$scale[0]->y+ 9483 $scale[-1]->height), 9484 ); 9485 9486 # fast ein Hack: Events im senkrechten Strich werden auf die 9487 # daruterliegenden Scales weitergeleitet 9488 if ($bar->can('eventGenerate')) { 9489 foreach my $evt (qw(Motion 9490 B1-Motion 1 ButtonRelease-1 9491 B2-Motion 2 ButtonRelease-2 9492 )) { 9493 my $evt2 = $evt; 9494 $bar->bind("<$evt2>" => sub { 9495 my $e = shift->XEvent; 9496 my($X,$Y) = ($e->X, $e->Y); 9497 # feststellen, welches Scale-Widget sich 9498 # darunter befindet 9499 my $wid = $bar->containing($X+5,$Y); 9500 if (defined $wid && $wid->isa('Tk::Scale')) { 9501 $wid->eventGenerate("<$evt2>", 9502 '-x' => $X-$wid->rootx, 9503 '-y' => $Y-$wid->rooty, 9504 ); 9505 } 9506 }); 9507 } 9508 } 9509 9510 my_popup($t); 9511 9512} 9513 9514# Berechnet f�r die Watt-Zahl die entsprechende Geschwindigkeit 9515### AutoLoad Sub 9516sub power2speed { 9517 my($power, %args) = @_; 9518 return if !$bp_obj; 9519 my $new_bp_obj = clone BikePower $bp_obj; 9520 $new_bp_obj->given('P'); 9521 $new_bp_obj->headwind(0); 9522 my $grade = $args{-grade} || 0; 9523 $new_bp_obj->grade($grade); 9524 $new_bp_obj->power($power); 9525 $new_bp_obj->calc; 9526 $new_bp_obj->velocity*3.6; 9527} 9528 9529# Berechnet f�r die angegebene Geschwindigkeit die Watt-Zahl 9530### AutoLoad Sub 9531sub speed2power { 9532 my($speed, %args) = @_; 9533 return if !$bp_obj; 9534 my $new_bp_obj = clone BikePower $bp_obj; 9535 $new_bp_obj->given('v'); 9536 $new_bp_obj->headwind(0); 9537 my $grade = $args{-grade} || 0; 9538 $new_bp_obj->grade($grade); 9539 $new_bp_obj->velocity($speed/3.6); 9540 $new_bp_obj->calc; 9541 $new_bp_obj->power; 9542} 9543 9544# Berechnet den Faktor f�r die max. Geschwindigkeit, die auf der 9545# jeweiligen Stra�e (wegen Belag, Kategorie ...) gefahren werden kann. 9546### AutoLoad Sub 9547sub max_speed { 9548 my($speed_belag) = @_; 9549 my $speed_radler = get_active_speed(); 9550 if ($speed_belag <= 0) { 9551 require Carp; 9552 Carp::cluck("Division by zero protection"); 9553 return $speed_radler; 9554 } 9555 ($speed_belag >= $speed_radler 9556 ? 1 9557 : $speed_radler/$speed_belag); 9558} 9559 9560# Return active speed in km/h. 9561### AutoLoad Sub 9562sub get_active_speed { 9563 my $speed; 9564 if ($active_speed_power{Type} eq 'power') { 9565 $speed = power2speed($power[$active_speed_power{Index}]); 9566 } else { 9567 $speed = $speed[$active_speed_power{Index}]; 9568 } 9569 if (!$speed) { 9570 $speed = 20; # f�r alle F�lle 9571 } 9572 $speed; 9573} 9574 9575sub toggle_mouse_help { 9576 if (defined $toplevel{"help"} and 9577 Tk::Exists($toplevel{"help"})) { 9578 $toplevel{"help"}->destroy; 9579 } else { 9580 mouse_help(); 9581 } 9582} 9583 9584# Gibt ein Hilfsfenster mit der derzeitigen Maustastenbelegung aus 9585### AutoLoad Sub 9586sub mouse_help { 9587 my $bgcolor = 'grey80'; 9588 my $help_t = redisplay_top($top, 'help', 9589 -title => M"Maushilfe", 9590 @popup_style, 9591 -bg => $bgcolor); 9592 return if !defined $help_t; 9593 $help_t->protocol('WM_DELETE_WINDOW' => sub { 9594 $show_mouse_help = 0; 9595 $help_t->destroy; 9596 }); 9597 my $row = 0; 9598 $help_t->gridColumnconfigure($_, -minsize => "1.6i") for (0..2); 9599 $help_t->gridRowconfigure($row, -minsize => "0.7i"); 9600 $help_t->Message(-textvariable => \$mouse_text[1], 9601 -width => "1.5i", 9602 -bg => $bgcolor, 9603 )->grid(-row => $row+1, -column => 0, -sticky => 'ne'); 9604 $help_t->Message(-textvariable => \$mouse_text[2], 9605 -width => "1.5i", 9606 -bg => $bgcolor, 9607 )->grid(-row => $row, -column => 1, -sticky => 's'); 9608 $help_t->Message(-textvariable => \$mouse_text[3], 9609 -width => "1.5i", 9610 -bg => $bgcolor, 9611 )->grid(-row => $row+1, -column => 2, -sticky => 'nw'); 9612 $row++; 9613 # Maus zeichnen 9614 my $c = $help_t->Canvas(-width => "1.13i", -height => "1.38i", 9615 -bg => $bgcolor, 9616 -borderwidth => 0, 9617 -highlightthickness => 0, 9618 -takefocus => 0, 9619 )->grid(-row => $row, -column => 1); 9620 $c->create('rectangle',"0.070866i","0.070866i","1.062992i","1.311024i", 9621 -fill => 'white', 9622 -outline => undef); 9623 $c->create('line',"1.062992i","1.311024i","1.062992i","0.070866i","0.070866i","0.070866i","0.070866i","1.311024i","1.062992i","1.311024i"); 9624 $c->create('line',"0.744094i","0.122047i","1.027559i","0.122047i","1.027559i","0.531496i","0.744094i","0.531496i","0.744094i","0.122047i"); 9625 $c->create('line',"0.425197i","0.122047i","0.708661i","0.122047i","0.708661i","0.531496i","0.425197i","0.531496i","0.425197i","0.122047i"); 9626 $c->create('line',"0.106299i","0.122047i","0.389764i","0.122047i","0.389764i","0.531496i","0.106299i","0.531496i","0.106299i","0.122047i"); 9627 $c->create('line', "0.106299i", "0.318898i", "0.000000i", "0.318898i"); 9628 $c->create('line', "1.133858i", "0.318898i", "1.027559i", "0.318898i"); 9629 $c->create('line', "0.562992i", "0.007874i", "0.562992i", "0.114173i"); 9630} 9631 9632## DEBUG_BEGIN 9633#BEGIN{mymstat("50% BEGIN");} 9634## DEBUG_END 9635 9636# L�dt bzw. speichert eine Route 9637### AutoLoad Sub 9638sub load_save_route { 9639 my($save, $file, %args) = @_; 9640 status_message(""); 9641 my $path; 9642 my $ext = $bbbike_route_ext; 9643 my $interactively_selected_filename = 0; 9644 if (!defined $file) { 9645 my $method = $save ? "getSaveFile" : "getOpenFile"; 9646 $file = $top->$method 9647 (-title => ($save ? M"Route speichern" : M"Route laden"), 9648 -initialdir => $oldpath, 9649 ($save ? 9650 (-defaultextension => ".$ext") : 9651 (-filetypes => [[M"Route-Dateien", '.' . $bbbike_route_ext], 9652 [M"GPSMan-Tracks", ['.tracks','.trk']], 9653 [M"GPSMan-Routen", ['.rte']], 9654 [M"G7toWin", ['.g7t', '.G7T']], 9655 [M"MPS-Tracks", ['.mps', '.MPS']], 9656 [M"Alle Dateien", '*']]), 9657 )); 9658 return if !defined $file; 9659 $oldpath = dirname $file; 9660 $interactively_selected_filename = 1; 9661 } 9662 if (!-f $file && !file_name_is_absolute($file)) { # unvollst�ndiger Dateiname 9663 $file = catfile($bbbike_routedir, "$file.$ext"); 9664 } 9665 if (!$save) { # load 9666 IncBusy($top) if $top; 9667 eval { 9668 9669 my $res = Route::load($file, 9670 { ResetRoute => \&reset_undo_route }, 9671 -fuzzy => 0); 9672 9673 if ($res->{IsStrFile}) { 9674 # eine Strassen-Datei 9675 plot_layer('str', $file); 9676 return; 9677 } 9678 9679 @realcoords = @{ $res->{RealCoords} }; 9680 @search_route_points = @{ $res->{SearchRoutePoints} }; 9681 9682 if (!@realcoords) { 9683 die M"Leere Routendatei"; 9684 } 9685 9686 add_last_loaded($file, $last_loaded_obj) if $interactively_selected_filename; 9687 @coords = (); 9688 my $i; 9689 my($minx, $miny, $maxx, $maxy); 9690 my $std = ($coord_system eq 'standard'); 9691 foreach (@realcoords) { 9692 my($x, $y); 9693 if ($std) { 9694 ($x, $y) = transpose($_->[0], $_->[1]); 9695 } else { 9696 ($x, $y) = transpose 9697 ($coord_system_obj->standard2map($_->[0], $_->[1])); 9698 require BBBikeAdvanced; 9699 buttonpoint($x, $y); 9700 }; 9701 push(@coords, [$x, $y]); 9702 if (!defined $minx || $x < $minx) { $minx = $x } 9703 if (!defined $maxx || $x > $maxx) { $maxx = $x } 9704 if (!defined $miny || $y < $miny) { $miny = $y } 9705 if (!defined $maxy || $y > $maxy) { $maxy = $y } 9706 } 9707 9708 if ($zoom_loaded_route) { 9709 zoom_view($minx, $miny, $maxx, $maxy); 9710 } elsif ($center_loaded_route) { 9711 my $x2 = 9712 (abs($coords[0]->[0]-$minx) > abs($coords[0]->[0]-$maxx) 9713 ? $minx : $maxx); 9714 my $y2 = 9715 (abs($coords[0]->[1]-$miny) > abs($coords[0]->[1]-$maxy) 9716 ? $miny : $maxy); 9717 $c->center_view2($coords[0]->[0], $coords[0]->[1], $x2, $y2); 9718 } 9719 9720 restore_search_route_points(); 9721 9722 redraw_path(); 9723 updatekm(); 9724 update_route_strname(); 9725 9726 undef $search_route_flag; 9727 search_route_mouse_cont(); 9728 9729 status_message(Mfmt("Typ der Routendatei: %s, Punkte: %s", $res->{Type}, scalar(@realcoords)), "info"); 9730 }; 9731 9732 if ($@) { 9733 status_message($@, 'err'); 9734 } 9735 DecBusy($top) if $top; 9736 } else { # Save 9737 my $case = ($os eq 'win' ? '(?i)' : ''); 9738 if ($file !~ /$case\.$ext$/i) { 9739 $file .= ".$ext"; 9740 } 9741 make_backup($file); 9742 eval { 9743 Route::save(-file => $file, 9744 -realcoords => \@realcoords, 9745 -searchroutepoints => \@search_route_points); 9746 }; 9747 if ($@) { 9748 status_message($@, 'err'); 9749 } else { 9750 add_last_loaded($file, $last_loaded_obj) if $interactively_selected_filename; 9751 } 9752 } 9753} 9754 9755### AutoLoad Sub 9756sub save_route_as_bbd { 9757 require Route; 9758 require Route::Heavy; 9759 my $file = $top->getSaveFile(-defaultextension => '.bbd'); 9760 return unless defined $file; 9761 my $tmpfile = "$tmpdir/bbbike-$<-$$.bbr"; 9762 load_save_route(1, $tmpfile); 9763 my $s = Route::as_strassen($tmpfile, 9764 name => "Route", 9765 cat => "X", 9766 fuzzy => 0, 9767 ); 9768 if (!$s) { 9769 status_message("Fataler Fehler: $tmpfile l�sst sich nicht konvertieren", "die"); 9770 } 9771 9772 $s->write($file); 9773 9774 unlink $tmpfile; 9775} 9776 9777### AutoLoad Sub 9778sub save_route_as_esri { 9779 my $file = $top->getSaveFile(-defaultextension => '.shp'); 9780 return unless defined $file; 9781 $file =~ s/\.shp$//; 9782 my $tmpfile1 = "$tmpdir/bbbike-$<-$$.bbr"; 9783 my $tmpfile2 = "$tmpdir/bbbike-$<-$$.bbd"; 9784 load_save_route(1, $tmpfile1); 9785 eval { 9786 # XXX Better diagnostics. bbr2bbd and bbd2esri should be 9787 # callable as modules. 9788 system("$FindBin::RealBin/miscsrc/bbr2bbd", $tmpfile1, $tmpfile2); 9789 status_message(Mfmt("Das Ausf�hren von %s ist mit dem Code %s fehlgeschlagen", "bbr2bbd", $?), "die") if $? != 0; 9790 system("$FindBin::RealBin/miscsrc/bbd2esri", $tmpfile2, "-o", $file); 9791 status_message(Mfmt("Das Ausf�hren von %s ist mit dem Code %s fehlgeschlagen", "bbd2esri", $?), "die") if $? != 0; 9792 }; warn $@ if $@; 9793 unlink $tmpfile2; 9794 unlink $tmpfile1; 9795} 9796 9797### AutoLoad Sub 9798sub save_route_as_optimized_gpx { 9799 gps_interface('BBBikeGPS::GPXRoute', -noloading => 1); 9800} 9801 9802### AutoLoad Sub 9803sub send_route_to_gps { 9804 if (!@{ get_act_search_route() }) { 9805 status_message(M"Keine Route", "infodlg"); 9806 return; 9807 } 9808 if ($os eq 'win') { 9809 # Assume that the windows distribution has gpsbabel bundled, 9810 # so always prefer this one 9811 require GPS::Gpsbabel; 9812 if (GPS::Gpsbabel->gpsbabel_available) { 9813 gps_interface('BBBikeGPS::GpsbabelSend', -noloading => 1); 9814 } else { 9815 require BBBikeGPS; 9816 if (GPS::BBBikeGPS::MapSourceSend->has_mapsource) { 9817 gps_interface('BBBikeGPS::MapSourceSend', -noloading => 1); 9818 } else { 9819 if ($gps_device ne 'USB' && eval { require GPS::DirectGarmin; 1 }) { 9820 gps_interface('DirectGarmin'); 9821 } else { 9822 my $recommended_path = GPS::Gpsbabel->gpsbabel_recommended_path; 9823 my $download_location = GPS::Gpsbabel->gpsbabel_download_location; 9824 # XXX use hypertext_widget 9825 status_message(<<EOF, "die"); 9826Das Programm gpsbabel wird zur �bertragung zum GPS-Ger�t ben�tigt und muss noch installiert werden. gpsbabel gibt es hier zum Download: 9827$download_location 9828 9829Die heruntergeladene .zip-Datei sollte im Verzeichnis 9830$recommended_path 9831ausgepackt werden. 9832EOF 9833 } 9834 } 9835 } 9836 } else { 9837 gps_interface('DirectGarmin'); 9838 } 9839} 9840 9841# weiter zur Druckfunktion... 9842### AutoLoad Sub 9843sub print_function { 9844 my $print_backend = $print_backend; 9845 if (!defined $print_backend || $print_backend eq "") { 9846 if ($os eq 'win') { 9847 my $available = print_postscript(undef, -checkavailability => 1); 9848 if (!$available) { 9849 # a PDF viewer should be available everywhere nowadays on Win32 9850 $print_backend = "pdf"; 9851 } else { 9852 $print_backend = "ps"; 9853 } 9854 } else { 9855 $print_backend = "ps"; 9856 } 9857 } 9858 9859 if ($print_backend eq 'pdf') { 9860 require File::Temp; 9861 my($fh, $tmpfile) = File::Temp::tempfile(UNLINK => 1, 9862 SUFFIX => ".pdf"); 9863 $tmpfiles{$tmpfile}++; 9864 pdf_export(-visiblemap => 1, -file => $tmpfile); 9865 close($fh); 9866 if (-e $tmpfile && -s $tmpfile) { 9867 view_pdf($tmpfile); 9868 } 9869 return; 9870 } 9871 9872 return if slow_postscript_generation(); 9873 9874 my $tmpfile = create_postscript 9875 ($c, 9876 -legend => ($use_legend ? 9877 ($use_legend_right ? 'right' : 'left') : 0), 9878 -colormode => $ps_color, 9879 -rotate => $ps_rotate, 9880 -scale_a4 => $ps_scale_a4, 9881 ); 9882 my @print_args; 9883 if ($ps_scale_a4) { 9884 push @print_args, -media => 'A4'; 9885 } 9886 print_postscript($tmpfile, @print_args); 9887} 9888 9889# Berechnet die Canvas-Koordinaten der Route aus den Standard-Koordinaten 9890### AutoLoad Sub 9891sub realcoords2coords { 9892 @coords = (); 9893 my $i; 9894 my $std = ($coord_system eq 'standard'); 9895 foreach (@realcoords) { 9896 my($x, $y); 9897 if ($std) { 9898 ($x, $y) = transpose($_->[0], $_->[1]); 9899 } else { 9900 ($x, $y) = transpose 9901 ($coord_system_obj->standard2map($_->[0], $_->[1])); 9902 } 9903 push @coords, [$x, $y]; 9904 } 9905} 9906 9907###################################################################### 9908# 9909# Funktionen zum Zeichnen der Kartenelemente (Strecken und Punkte) 9910# 9911# Allegemeine Plot-Funktion 9912sub plot { 9913 my($type, $abk, %args) = @_; 9914 Hooks::get_hooks("before_plot")->execute; 9915 if (exists $args{'-draw'}) { 9916 if ($type eq 'str') { 9917 $str_draw{$abk} = $args{'-draw'}; 9918 } else { 9919 $p_draw{$abk} = $args{'-draw'}; 9920 } 9921 } 9922 if ($type eq 'str') { 9923 plotstr($abk, %args); 9924 } elsif ($type eq 'p') { 9925 if ($abk =~ /sperre/) { 9926 my $object_or_file = $args{-object} || $args{-filename} || $p_obj{$abk}; 9927 $args{-abk} = $abk; 9928 plot_sperre($object_or_file, %args); 9929 } else { 9930 plotp($abk, %args); 9931 } 9932 } else { 9933 die "Unknown type $type"; 9934 } 9935###XXX H�h? 9936# if ($BBBikeLazy::mode && defined &bbbikelazy_remove_data) { 9937# bbbikelazy_remove_data($type, $abk); 9938# } 9939 Hooks::get_hooks("after_plot")->execute; 9940} 9941 9942sub plot_layer { 9943 my($type, $file, %args) = @_; 9944 my $abk = next_free_layer(); 9945 if (!defined $abk) { 9946 status_message("Kein freier Layer mehr vorhanden", "err"); 9947 return; 9948 } 9949 fix_stack_order($abk); 9950 if ($type eq 'p') { 9951 $p_draw{$abk} = 1; 9952 if (defined $file) { 9953 $p_file{$abk} = $file; 9954 delete $p_obj{$abk}; 9955 } 9956 } else { 9957 $str_draw{$abk} = 1; 9958 if (defined $file) { 9959 $str_file{$abk} = $file; 9960 delete $str_obj{$abk}; 9961 } 9962 } 9963 plot($type, $abk, %args); 9964 if ($type eq 'p' && $p_draw{$abk}) { 9965 $most_recent_p_layer = $abk; 9966 } elsif ($type eq 'str' && $str_draw{$abk}) { 9967 $most_recent_str_layer = $abk; 9968 } 9969 $abk; 9970} 9971 9972# XXX 9973# h�heres Canvas-Objekt 9974# - derzeitige Transpose-Funktion 9975# - Scale 9976# - Koordinatensystem 9977# 9978# Zeichnet Strecken auf dem Canvas 9979sub plotstr { 9980 my($abk, %args) = @_; 9981 my $c = $c; 9982 return if !$c; 9983 my $std = 1; 9984 my $transpose = \&transpose; 9985 if (exists $args{Canvas}) { 9986 $c = $args{Canvas}; 9987 $std = 0; 9988 $transpose = ($show_overview_mode eq 'region' 9989 ? \&transpose_small 9990 : \&transpose_medium); 9991 } 9992 9993 status_message(""); 9994 $abk = 's' if !defined $abk; 9995 9996 # alte Tags l�schen 9997 if (!$std || !$args{FastUpdate} || !$str_draw{$abk}) { 9998 $c->delete($abk); # evtl. alte Koordinaten l�schen 9999 $c->delete("pp-$abk"); 10000 } 10001 $c->delete("$abk-out"); 10002 $c->delete("$abk-label"); 10003 $c->delete("$abk-label-bg"); 10004 $c->delete("$abk-fg") if $abk eq 'v'; # XXX do not use for "b", "r" or "u"! 10005 if ($abk eq 'w') { # Wasser *und* Inseln l�schen 10006 $c->delete("i"); 10007 $c->delete("i-out"); 10008 $c->delete("i-label"); 10009 $c->delete("i-label-bg"); 10010 } 10011 10012 if ($std && !$str_draw{$abk}) { 10013 if ($lazy_str{$abk}) { 10014 bbbikelazy_remove_data("str", $abk); 10015 } 10016 status_message(Mfmt("Layer <%s> entfernt", exists $str_attrib{$abk} ? $str_attrib{$abk}->[ATTRIB_PLURAL] : $abk), "info"); 10017 return; 10018 } 10019 # A hack to get overview canvas plots deleted 10020 if (exists $args{Canvas} && exists $args{-draw} && !$args{-draw}) { 10021 return; 10022 } 10023 10024 # Get source from filename or street object 10025 my($filename, $filename_maybe, $str, $has_filename); 10026 if (!defined $args{-object}) { 10027 $filename = $args{-filename} || $args{Filename}; 10028 if (defined $filename) { 10029 $str_file{$abk} = $filename; 10030 } else { 10031 $filename = get_strassen_file($str_file{$abk}); 10032 $filename_maybe = $str_file{$abk} if $edit_mode_flag; # as fallback if no -orig version available 10033 } 10034 $has_filename = 1; 10035 delete $pending{"replot-str-$abk"}; 10036 if (!defined $filename) { 10037 status_message(Mfmt("Dateiname f�r <%s> ist nicht definiert.", $abk), 10038 'err'); 10039 return; 10040 } 10041 } else { 10042 $str = delete $args{-object}; 10043 } 10044 10045# # Radwege werden im Edit-Modus besser mit radweg_draw_canvas() gezeichnet 10046# # XXX ups? stimmt das noch immer??? -> wahrscheinlich nicht! XXX 10047# if ($abk eq 'rw' and $coord_system ne 'standard') { 10048# radweg_open(); 10049# radweg_draw_canvas(); 10050# return; 10051# } 10052 10053 my $dont_use_cache; 10054 my $dont_set_cache = 1; 10055 10056 if (!$str) { 10057 $dont_use_cache = ($coord_system ne 'standard' || 10058 $args{FastUpdate}); 10059 $dont_set_cache = ($coord_system ne 'standard'); 10060 TRYCACHE: { 10061 if (defined $str_obj{$abk} && !$dont_use_cache) { 10062 last TRYCACHE if ($abk eq 'l' and 10063 (defined $str_cache_attr{'l'} and 10064 $str_cache_attr{'l'} ne "$str_far_away{'l'}")); 10065 last TRYCACHE if ($str_regions{'l'} && @{$str_regions{'l'}}); 10066 last TRYCACHE if !$str_obj{$abk}->is_current; 10067 $str = $str_obj{$abk}; 10068 } 10069 } 10070 } 10071 10072 if (!defined $str) { 10073 cache_decider_init(); 10074 # XXX use get_any_strassen_obj? 10075 if ($abk eq 'w') { 10076 $str = _get_wasser_obj($filename); 10077 } elsif ($abk eq 'l') { 10078 $str = _get_landstr_obj(); 10079 } elsif ($abk eq 'e') { 10080 $str = _get_ferry_obj(); 10081 } elsif ($abk eq 'comm') { 10082 $str = _get_comments_obj(); 10083 } elsif ($abk eq 'fz') { 10084 $str = _get_fragezeichen_obj(); 10085 } else { 10086 eval { $str = Strassen->new($filename); }; 10087 if ($@ && $filename_maybe) { 10088 eval { $str = Strassen->new($filename_maybe); }; 10089 } 10090 if ($@) { 10091 if ($edit_mode || $edit_normal_mode) { 10092 status_message(Mfmt("Beim Laden der Datei %s: %s", $filename, $@), "info"); 10093 return; 10094 } 10095 # Do not "die", may be in Progress mode 10096 if (!$no_original_datadir) { 10097 $str_draw{$abk} = 0; 10098 status_message($@, "err"); 10099 } 10100 return; 10101 } 10102 } 10103 if ($abk ne 'w') { # XXX get_cache_identifier benutzen 10104 if ((!$dont_set_cache && cache_decider()) || 10105 $abk =~ /^[sl]$/ || 10106 $edit_normal_mode # Always cache in edit mode to make "reload all" work 10107 ) { 10108 # f�r nearest_line_points Caching erzwingen 10109 $str_obj{$abk} = $str; 10110 if ($abk eq 'l') { 10111 $str_cache_attr{'l'} = "$str_far_away{'l'}"; 10112 # XXX str_regions? 10113 } 10114 } 10115 } 10116 } 10117 10118 if (!defined $str) { 10119 status_message(M"Kein Objekt definiert!", "err"); 10120 return; 10121 } 10122 10123 handle_global_directives($str, $abk); 10124 # XXX obsolete: 10125 if (defined $filename && -e "$filename.desc") { 10126 require BBBikeAdvanced; 10127 read_desc_file("$filename.desc", $abk); 10128 } 10129 10130 if ($str_name_draw{$abk}) { 10131 require Tk::RotFont; 10132 } 10133 10134 my $lazy = defined $args{-lazy} ? $args{-lazy} : $lazy_plot; 10135 if ($std && $lazy && $has_filename) { 10136 status_message(Mfmt("Layer <%s> gezeichnet", exists $str_attrib{$abk} ? $str_attrib{$abk}->[ATTRIB_PLURAL] : $abk), "info"); 10137 return bbbikelazy_add_data("str", $abk, $str, \%args); 10138 } 10139 10140 my $complete_str = $str; 10141 my $diffed_str = 0; 10142 my $indexmap; 10143 if ($args{FastUpdate}) { 10144 my($new_str, $todelref); 10145 ($new_str, $todelref, $indexmap) = $str->diff_orig(-clonefile => 1); 10146 if (!defined $new_str) { 10147 print STDERR M("Diff-Ausgabe wird nicht verwendet"), "\n" if $verbose; 10148 $c->delete($abk); # evtl. alte Koordinaten l�schen 10149 $c->delete("pp-$abk"); 10150 } else { 10151 if ($verbose) { 10152 print STDERR M("Diff-Ausgabe wird verwendet"), "\n"; 10153 print STDERR Mfmt("Anzahl der neu zu zeichnenden Stra�en: %d", scalar @{$new_str->data}), "\n"; 10154 print STDERR Mfmt("Anzahl der zu l�schenden Stra�en: %d", scalar @$todelref), "\n"; 10155 } 10156 for my $id (@$todelref) { 10157 for my $strdeladd ("", "-label") { 10158 $c->delete("$abk$strdeladd-$id"); 10159 } 10160 } 10161 $str = $new_str; 10162 $diffed_str = 1; 10163 } 10164 } 10165 10166 my($restrict, $restrict_list, $ignore, $ignore_list) = _set_restrict($abk); 10167 10168 my %category_color = %category_color; 10169 if ($abk =~ /^g(|[PD])$/ && !$std) { 10170 $category_color{Z} = '#9e9e9e'; 10171 } 10172 10173 my $default_width = get_line_width($abk) || 4; 10174 if (defined $args{Width}) { $default_width = $args{Width} } 10175 my %category_width; # XXX the global category_width is ignored!!! should be changed 10176 { 10177 my $scale = (exists $args{Canvas} 10178 ? ($show_overview_mode eq 'region' 10179 ? $small_scale 10180 : $medium_scale) 10181 : $scale); 10182 %category_width = _set_category_width($abk, $scale); 10183 } 10184 10185 # current category size 10186 my %category_size = map { 10187 ($_, $category_size{$_}* $label_font_size/10) 10188 } keys %category_size; 10189 10190 my $no_overlap_label = (exists $args{NoOverlapLabel} 10191 ? $args{NoOverlapLabel} : $no_overlap_label{$abk}); 10192 10193 my $coordsys = $coord_system_obj->coordsys; 10194 10195 my $use_stippleline = decide_stippleline($abk); 10196 10197 destroy_delayed_restack(); 10198 10199 IncBusy($top); 10200 $progress->Init(-dependents => $c, 10201 (defined $filename ? (-label => $filename) : ()), 10202 ); 10203 10204 my %conv_args; 10205 if ($args{-map}) { 10206 $conv_args{Map} = $args{-map}; 10207 } 10208 my $conv = $str->get_conversion(%conv_args); 10209 10210 eval { 10211 # XXX Experiment 10212 if ($orientation eq 'landscape' && 10213 !$edit_mode && 10214#XXX? !$edit_normal_mode && 10215 !$str_name_draw{$abk} && 10216 !$str_nr_draw{$abk} && 10217 !exists $args{Canvas} && 10218 !$p_draw{'pp'} && 10219 ($abk eq 'l' || $abk eq 's') && 10220 !$conv && 10221 defined &BBBike::fast_plot_str) { 10222 eval { 10223 die if $str->isa("Strassen::Storable"); 10224 # Wenn outline nicht definiert ist, dann wird es 10225 # eigenm�chtig gesetzt. Die XS-Routine ist daf�r schnell 10226 # genug. 10227 if (!defined $str_outline{$abk}) { 10228 $str_outline{$abk} = 1; 10229 } 10230 my(@files) = $str->file; 10231 if (grep { /\.gz$/ } @files) { 10232 die "fast_plot_str can't handle gzipped files yet"; 10233 } 10234 my(@args) = ($c, $abk, 10235 (@files > 1 ? \@files : @files), 10236 $progress); 10237 if (@$restrict_list) { 10238 push @args, $restrict_list; 10239 } else { 10240 push @args, undef; 10241 } 10242 push @args, \%category_width; 10243 if (@$ignore_list) { 10244 push @args, $ignore_list; 10245 } else { 10246 push @args, undef; 10247 } 10248 BBBike::fast_plot_str(@args); 10249 }; 10250 my $err = $@; 10251 if (!$err) { 10252 goto PLOTSTR_CONT; 10253 } else { 10254 warn $err if $^W; 10255 } 10256 } 10257 10258 my $xadd_anchor = $xadd_anchor_type->{$abk}; 10259 my $yadd_anchor = $yadd_anchor_type->{$abk}; 10260 my $label_spaceadd = $label_spaceadd{$abk}; 10261 10262 my $real_i = 0; 10263 my $i; 10264 my $anzahl_eindeutig = $str->count; 10265 $str->init; 10266 $escape = 0; 10267 my @extra_tags = ($abk =~ /^L\d+/ ? ("$abk-s") : ()); 10268 10269 my $draw_sub = eval $plotstr_draw_sub; 10270 string_eval_die($@, $plotstr_draw_sub) if $@; 10271 10272 my $bench = Tk::Time_So_Far(); 10273 while (1) { 10274 my $ret = $str->next; 10275 last if !@{$ret->[Strassen::COORDS]}; 10276 if (!$diffed_str) { 10277 if ($real_i % 80 == 0) { 10278 $progress->Update($real_i/$anzahl_eindeutig); 10279 # XXX Probleme mit diesem $top->update, falls 10280 # ein anderer plot-Vorgang damit gestartet wird 10281 #if ($progress) { 10282 #$top->update; # f�r Escape 10283 #if ($escape) { 10284 # status_message("Zeichnen von <$filename> abgebrochen", 10285 # "warn"); 10286 # last; 10287 # } 10288 #} 10289 } 10290 } 10291#last if $i > 100; # for Debugging XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 10292 10293 $i = $indexmap && exists $indexmap->{$real_i} ? $indexmap->{$real_i} : $real_i; 10294 $draw_sub->($ret); # XXX evtl. den Code mit eval erzeugen 10295 $real_i++; 10296 } 10297# XXXXXX can this ever happen? XXXXXXXXXXXXXXXXXXXXXXXXXXX 10298# XXX Yes: If a bbd file contains a half-valid line (with name and cat, but without coords) 10299if ($str->pos != scalar @{$str->{Data}}) { status_message("warning: " . $str->pos . " != " . scalar(@{$str->{Data}}) . "!", "dialog", "err") } 10300#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 10301 warn sprintf "Plotting streets '$abk' took %.3fs\n", Tk::Time_So_Far()-$bench 10302 if $verbose; 10303 10304 PLOTSTR_CONT: 10305 $c->itemconfigure('pp', 10306 -capstyle => $capstyle_round, 10307 -width => 5, 10308 ); 10309 pp_color(); 10310 if ($layer_active_color{$abk}) { 10311 $c->itemconfigure($abk, -activefill => $layer_active_color{$abk}); 10312 } 10313 if ($abk eq 'e' && defined $linestip) { 10314 # XXX hacky: make sure that e-img do not get configured, 10315 # so use 'e-Q' instead of just 'e' 10316 $c->itemconfigure('e-Q', -stipple => '@' . $linestip); 10317 } 10318 10319 if (!exists $args{Canvas} && !$no_make_net && !$edit_mode && !$edit_normal_mode) { 10320 if (defined $net && !$net->is_source($str) && $abk =~ /^[sl]$/) { 10321 make_net(); 10322 } elsif (!defined $net && $abk =~ /^[sl]$/) { 10323 make_net(); 10324 } 10325 } 10326 10327 if (($edit_mode || $edit_normal_mode || $abk eq 'relgps' || $args{FastUpdate})) { # XXX? and !$diffed_str) { 10328 warn "Try to copy original data" if $verbose; 10329 my $r = $complete_str->copy_orig; 10330 warn "Returned $r" if $verbose; 10331 } 10332 10333 if ($std) { 10334 restack_delayed(); # XXX check! 10335 } 10336 10337 if ($abk =~ /^L\d+/) { 10338 std_str_binding($abk); 10339 } 10340 10341 }; 10342 warn "eval called before line " . __LINE__ . ": $@" if ($@); 10343 $progress->Finish; 10344 DecBusy($top); 10345} 10346 10347sub _set_restrict { 10348 my($abk) = @_; 10349 my($restrict, @restrict, $ignore, @ignore); 10350 if (exists $str_restrict{$abk} || 10351 exists $str_ignore{$abk}) { 10352 my $all_set = 1; 10353 my($k,$v); 10354 if (exists $str_restrict{$abk}) { 10355 while(($k,$v) = each %{$str_restrict{$abk}}) { 10356 if (!$v) { 10357 $all_set = 0; 10358 } else { 10359 push @restrict, $k; 10360 } 10361 } 10362 } 10363 if (exists $str_ignore{$abk}) { 10364 while(($k,$v) = each %{$str_ignore{$abk}}) { 10365 if ($v) { 10366 $all_set = 0; 10367 push @ignore, $k; 10368 } 10369 } 10370 } 10371 if (exists $str_restrict{$abk}) { 10372 if ($all_set || !@restrict) { 10373 undef $restrict; 10374 } else { 10375 $restrict = '^(' . join('|', map { quotemeta $_ } @restrict) . ")\$"; 10376 } 10377 } 10378 if (exists $str_ignore{$abk}) { 10379 $ignore = '^(' . join('|', map { quotemeta $_ } @ignore) . ")\$"; 10380 } 10381 if ($] >= 5.005) { 10382 eval q{ 10383 $restrict = qr/$restrict/ 10384 if defined $restrict; 10385 $ignore = qr/$ignore/ 10386 if defined $ignore; 10387 }; die $@ if $@; 10388 } 10389 } 10390 ($restrict, \@restrict, $ignore, \@ignore); 10391} 10392 10393#XXX %category_width wird nicht skaliert... 10394sub _set_category_width { 10395 my($abk, $this_scale) = @_; 10396 $this_scale = $scale if !defined $this_scale; 10397 my %category_width; 10398 foreach (keys %line_width) { 10399 if (/^$abk-(.*)/) { 10400 my $cat = $1; 10401 $category_width{$cat} = get_line_width($_, $this_scale); 10402 } 10403 } 10404 %category_width; 10405} 10406 10407sub decide_stippleline { 10408 my($abk) = @_; 10409 if ($Tk::VERSION < 800.016) { 10410 if (exists $line_dash{$abk} || exists $layer_line_dash{$abk} || exists $layer_category_line_dash{$abk}) { 10411 require Tk::StippleLine; 10412 return 1; 10413 } else { 10414 return 0; 10415 } 10416 } 10417 return 3; # signal that -dash exists or is needed 10418} 10419 10420# Arguments: 10421# $c: canvas to draw onto 10422# $x, $y: canvas coordinates 10423# %args: options for createText, special options are: 10424# -outlinecolor: color of the outline, by default canvas background 10425# -outlinewidth: width of the outline, by default 1 10426### AutoLoad Sub 10427sub outline_text { 10428 my($c, $x, $y, %args) = @_; 10429 my $outline_color = delete $args{'-outlinecolor'} || $c->cget(-background); 10430 my $fg = delete $args{'-fill'} || "black"; 10431 my $outline_width = delete $args{'-outlinewidth'} || 1; 10432 my $tags = delete $args{'-tags'}; 10433 $tags = [$tags] if ref $tags ne 'ARRAY'; 10434 $outline_i++; 10435 if (defined $outline_color && defined $outline_width) { 10436 my @outlines; 10437 foreach (1 .. $outline_width) { 10438 push(@outlines, [-$_, 0], [$_, 0], [0, $_], [0, -$_]); 10439 } 10440 foreach (@outlines) { 10441 $c->createText($x + $_->[0], $y + $_->[1], 10442 -fill => $outline_color, 10443 -tags => [@$tags, 'outlslave-'.$outline_i, 10444 'outldata_'.join("_",@$_)], 10445 %args); 10446 } 10447 } 10448 $c->createText($x, $y, 10449 -fill => $fg, 10450 -tags => [@$tags, 'outlmaster', 'outlmaster-'.$outline_i, 10451 "outlmaster-width-$outline_width"], 10452 %args); 10453} 10454 10455### AutoLoad Sub 10456sub plot_mount { 10457 my $mount; 10458 if ($str_draw{'mount'}) { 10459 my $comm = Strassen->new(get_strassen_file("comments_mount")); 10460 my $comm_mount = Strassen->new_copy_restricted($comm, -grep => ["St;"]); 10461 $mount = MultiStrassen->new($str_file{"mount"}, 10462 $comm_mount); 10463 } 10464 plot('str','mount', -object => $mount); 10465} 10466 10467# Zeichnet gesperrte Stra�en und Einbahnstra�en. 10468# XXX gesperrte Wegf�hrungen werden noch nicht gezeichnet 10469### AutoLoad Sub 10470sub plot_sperre { 10471 my $file_or_object = shift; 10472 my %args = @_; 10473 my $abk = $args{-abk} || 'sperre'; 10474 Hooks::get_hooks("before_plot")->execute; 10475 if (!$args{FastUpdate}) { 10476 $c->delete($abk); 10477 } 10478 if (!$p_draw{$abk}) { 10479 Hooks::get_hooks("after_plot")->execute; # XXX should not be here 10480 status_message(Mfmt("Layer <Sperrungen> entfernt"), "info"); 10481 return; 10482 } 10483 IncBusy($top); 10484 eval { 10485 my $gesperrt; 10486 if (UNIVERSAL::isa($file_or_object, "Strassen")) { 10487 $gesperrt = $file_or_object; 10488 } else { 10489 $gesperrt = new Strassen (defined $file_or_object 10490 ? $file_or_object 10491 : get_strassen_file($sperre_file) 10492 ); 10493 } 10494 $p_obj{$abk} = $gesperrt; 10495 my $is_car = $gesperrt->file =~ /gesperrt_car/; 10496 my $car_photo; 10497 if ($is_car) { 10498 $car_photo = load_photo($top, 'car'); 10499 } 10500 10501 my $width0 = get_line_width('sperre0'); 10502 my $width1 = get_line_width('sperre1'); 10503 my $width2 = get_line_width('sperre2'); 10504 my $width3 = get_line_width('sperre3'); 10505 my $width3_nocross = get_line_width('sperre3nocross'); 10506 my $length1 = get_line_length('sperre1'); 10507 my $length2 = get_line_length('sperre2'); 10508 10509 my %type2cat = 10510 (StrassenNetz::BLOCKED_ONEWAY() => "sperre1", 10511 StrassenNetz::BLOCKED_ONEWAY_STRICT() => "sperre1s", 10512 StrassenNetz::BLOCKED_COMPLETE() => "sperre2", 10513 StrassenNetz::BLOCKED_CARRY() => "sperre0", 10514 ); 10515 10516 my %type2fill = 10517 (StrassenNetz::BLOCKED_ONEWAY() => 10518 ($width1 && $length1 ? $category_color{'sperre1'} : undef), 10519 StrassenNetz::BLOCKED_ONEWAY_STRICT() => 10520 ($width1 && $length1 ? $category_color{'sperre1s'} : undef), 10521 ); 10522 my $fill2 = ($width2 && $length2 ? $category_color{'sperre2'} : undef); 10523 10524 # korrigieren, damit beim Vergr��ern etwas erscheint 10525 $length1 = ($length1 ? $length1 : 1); 10526 $length2 = ($length2 ? $length2 : 1); 10527 10528 # XXX don't duplicate code from plotstr! 10529 my $diffed_str = 0; 10530 my $str = $gesperrt; 10531 my $complete_str = $str; 10532 my $indexmap; 10533 if ($args{FastUpdate}) { 10534 my($new_str, $todelref); 10535 ($new_str, $todelref, $indexmap) = $str->diff_orig(-clonefile => 1); 10536 if (!defined $new_str) { 10537 print STDERR M("Diff-Ausgabe wird nicht verwendet") if $verbose; 10538 $c->delete($abk); # evtl. alte Koordinaten l�schen 10539 $c->delete("pp-$abk"); 10540 } else { 10541 if ($verbose) { 10542 print STDERR M("Diff-Ausgabe wird verwendet"), "\n"; 10543 print STDERR Mfmt("Anzahl der neu zu zeichnenden Objekte: %d", scalar @{$new_str->data}), "\n"; 10544 print STDERR Mfmt("Anzahl der zu l�schenden Objekte: %d", scalar @$todelref), "\n"; 10545 } 10546 foreach (@$todelref) { 10547 $c->delete("$abk-$_"); 10548 } 10549 $str = $new_str; 10550 $diffed_str = 1; 10551 $gesperrt = $str; 10552 } 10553 } 10554 10555 my %conv_args; 10556 if ($args{-map}) { 10557 $conv_args{Map} = $args{-map}; 10558 } 10559 my $conv = $gesperrt->get_conversion(%conv_args); 10560 10561 my $use_inwork_photo = get_symbol_scale('attrib-inwork'); 10562 10563 $gesperrt->init; 10564 my $real_pos = -1; 10565 while (1) { 10566 $real_pos++; 10567 my $pos = $indexmap && exists $indexmap->{$real_pos} ? $indexmap->{$real_pos} : $real_pos; 10568 my $ret = $gesperrt->next; 10569 my @kreuzungen = @{$ret->[Strassen::COORDS]}; 10570 last if !@kreuzungen; 10571 @kreuzungen = map { $conv->($_) } @kreuzungen 10572 if $conv; 10573 10574 my($icon_x, $icon_y, $icon_anchor); 10575 my $sub_cat; 10576 my($cat,$addinfo) = $ret->[Strassen::CAT] =~ m{^(.*?)(?:::?(.*))?$}; 10577 my @addinfo = $addinfo ? split(':', $addinfo): (); 10578 my %addinfo = map {($_,1)} @addinfo; 10579 if (!$edit_normal_mode) { # we want to see everything in edit mode 10580 next if $addinfo{'igndisp'}; 10581 } 10582 if ($cat eq StrassenNetz::BLOCKED_CARRY) { 10583 if ($width0) { # gr��er 0 10584 $sub_cat = 'sperre0'; 10585 my($x,$y) = 10586 transpose(@{Strassen::to_koord1($kreuzungen[0])}); 10587 10588 my $rad = deg2rad($addinfo[1] || 0); # addinfo[1] is angle 10589 my $cos4 = cos($rad)*4; 10590 my $sin4 = sin($rad)*4; 10591 for my $add ([-$cos4,$sin4], [0,0], [$cos4,-$sin4]) { 10592 my($yadd,$xadd) = @$add; 10593 $c->createLine 10594 ($x-$cos4+$xadd, ($y+$yadd)-$sin4, $x+$cos4+$xadd, ($y+$yadd)+$sin4, 10595 -width => $width0, # XXX $width0 verwenden und in get_line_width anpassen 10596 -tags => [$abk, $sub_cat, 10597 $ret->[Strassen::NAME], $abk.'-'.$pos], 10598 ); 10599 } 10600 ($icon_x, $icon_y, $icon_anchor) = ($x, $y, 'n'); 10601 } 10602 } elsif ($cat eq StrassenNetz::BLOCKED_NARROWPASSAGE) { 10603#XXX works, but write nicer... 10604 # if ($widthBNP) XXX 10605 $sub_cat = 'sperreBNP'; 10606 my($x,$y) = 10607 transpose(@{Strassen::to_koord1($kreuzungen[0])}); 10608 10609 my $rad = deg2rad($addinfo[1] || 0); # addinfo[1] is angle 10610 my $cos1 = cos($rad); 10611 my $sin1 = sin($rad); 10612 my $cos4 = cos($rad)*4; 10613 my $sin4 = sin($rad)*4; 10614 my $tags = [$abk, $sub_cat, $ret->[Strassen::NAME], $abk.'-'.$pos]; 10615 for my $add ([-$cos1,$sin1]) { 10616 my($yadd,$xadd) = @$add; 10617 $c->createLine 10618 ($x-$cos1+$xadd, ($y+$yadd)-$sin1, $x+$cos4+$xadd, ($y+$yadd)+$sin4, 10619 -width => $width0, # XXX $widthBNP verwenden und in get_line_width anpassen 10620 -tags => $tags, 10621 ); 10622 } 10623 for my $add ([$cos1,-$sin1]) { 10624 my($yadd,$xadd) = @$add; 10625 $c->createLine 10626 ($x-$cos4+$xadd, ($y+$yadd)-$sin4, $x+$cos1+$xadd, ($y+$yadd)+$sin1, 10627 -width => $width0, # XXX $widthBNP verwenden und in get_line_width anpassen 10628 -tags => $tags, 10629 ); 10630 } 10631 if ($addinfo{'trailer=no'} && $notrailer_photo) { 10632 my($xm,$ym) = ($x+$cos1-$sin1, $y+$cos1+$sin1); 10633 $c->createImage($xm,$ym, 10634 -anchor => 'nw', 10635 -image => $notrailer_photo, 10636 -tags => $tags); 10637 } 10638 ($icon_x, $icon_y, $icon_anchor) = ($x, $y, 'n'); 10639 } elsif ($cat =~ /^@{[ StrassenNetz::BLOCKED_ROUTE ]}(nocross)?/) { 10640 my $is_nocross = defined $1; 10641 $sub_cat = 'sperre3'; 10642 my @c; 10643 for(my $i = 0; $i <= $#kreuzungen; $i++) { 10644 push @c, map { transpose(@$_) } Strassen::to_koord1($kreuzungen[$i]); 10645 } 10646 10647 line_shorten(\@c); 10648 10649 if (!$is_nocross) { 10650 # move to the right 10651 my $delta = -3; 10652 for(my $i = 2; $i < $#c; $i+=2) { 10653 # atan2(y2-y1, x2-x1) 10654 my $alpha = atan2($c[$i+1]-$c[$i-1], $c[$i]-$c[$i-2]); 10655 my $beta = $alpha - pi()/2; 10656 my($dx, $dy) = ($delta*cos($beta), $delta*sin($beta)); 10657 $c[$i] += $dx; 10658 $c[$i+1] += $dy; 10659 if ($i == 2) { 10660 $c[0] += $dx; 10661 $c[1] += $dy; 10662 } 10663 } 10664 } 10665 10666 $c->createLine 10667 (@c, 10668 -width => (!$is_nocross ? $width3 : $width3_nocross), 10669 (!$is_nocross ? (-arrow => 'last', 10670 -arrowshape => [4,6,3], 10671 -smooth => 1, 10672 -fill => 'red', 10673 ) 10674 : (-fill => '#ff4500', 10675 ) 10676 ), 10677 ($Tk::VERSION >= 800.016 ? (-dash => $line_dash{sperre3}) : ()), 10678 -tags => [$abk, $sub_cat, 10679 $ret->[Strassen::NAME], $abk.'-'.$pos], 10680 ); 10681 ($icon_x, $icon_y, $icon_anchor) = ($c[0], $c[1], 'n'); 10682 } else { 10683 $sub_cat = $type2cat{$cat}; 10684 if ($cat eq StrassenNetz::BLOCKED_COMPLETE && $#kreuzungen == 0) { 10685 # ein bisschen schummeln ... 10686 push @kreuzungen, $kreuzungen[0]; 10687 } 10688 my $tags = [$abk, $sub_cat, 10689 $ret->[Strassen::NAME], $abk.'-'.$pos]; 10690 10691 my $plot_one = sub { 10692 my($p_ref, $inx) = @_; 10693 my($x1,$y1) = 10694 transpose(@{Strassen::to_koord1($p_ref->[$inx])}); 10695 my($x2,$y2) = 10696 transpose(@{Strassen::to_koord1($p_ref->[$inx+1])}); 10697 my($xm,$ym) = (int(($x2-$x1)/2+$x1), int(($y2-$y1)/2+$y1)); 10698 10699 if ($cat eq StrassenNetz::BLOCKED_ONEWAY || 10700 $cat eq StrassenNetz::BLOCKED_ONEWAY_STRICT) { 10701 my $alpha = atan2($y2-$y1, $x2-$x1); 10702 my($xd,$yd) = ($length1*cos($alpha), 10703 $length1*sin($alpha)); 10704 $c->createLine($xm+$xd, $ym+$yd, $xm-$xd, $ym-$yd, 10705 -fill => $type2fill{$cat}, 10706 -width => $width1, 10707 -arrow => 'last', 10708 -arrowshape => [4,6,3], 10709 -tags => $tags, 10710 ); 10711 } elsif ($cat eq StrassenNetz::BLOCKED_COMPLETE) { 10712 # $c->createImage($xm,$ym, 10713 # -image => $blocked_photo, 10714 # -tags => $tags); 10715 $c->createLine($xm-$length2, $ym-$length2, 10716 $xm+$length2, $ym+$length2, 10717 -fill => $fill2, 10718 -width => $width2, 10719 -tags => $tags); 10720 $c->createLine($xm-$length2, $ym+$length2, 10721 $xm+$length2, $ym-$length2, 10722 -fill => $fill2, 10723 -width => $width2, 10724 -tags => $tags); 10725 } 10726 10727 my @anchors = qw(nw sw ne se); 10728 10729 # Add an additional icon 10730 for my $check (['inwork', $use_inwork_photo], 10731 ['night', $night_photo], 10732 ['clock', $clock_photo], 10733 ['tempmaybe', $cal_questionmark_photo], 10734 ['temp', $cal_photo], # should be last 10735 ) { 10736 my($addinfo, $photo) = @$check; 10737 if ($addinfo{$addinfo} && $photo) { 10738 $c->createImage($xm,$ym, 10739 -anchor => shift(@anchors), 10740 -image => $photo, 10741 -tags => [@$tags,"attrib-$addinfo"]); 10742 last; 10743 } 10744 } 10745 10746 if ($is_car && $car_photo) { 10747 $c->createImage($xm, $ym, 10748 -image => $car_photo, 10749 -anchor => shift(@anchors), 10750 -tags => [$abk, $sub_cat,$ret->[Strassen::NAME], $abk.'-'.$pos]); 10751 } 10752 }; 10753 10754 if ($advanced) { # XXX decide one day if this should be the default 10755 # "Sparse plotting": only one symbol between a 10756 # crossing-limited hop. 10757 my @hops = split_by_crossings(@kreuzungen); 10758 for my $hop (@hops) { 10759 my $inx; 10760 if ($cat eq StrassenNetz::BLOCKED_ONEWAY || 10761 $cat eq StrassenNetz::BLOCKED_ONEWAY_STRICT) { 10762 $inx = $#{$hop}-1; 10763 } elsif ($cat eq StrassenNetz::BLOCKED_COMPLETE) { 10764 $inx = int($#{$hop}/2); 10765 } else { 10766 # may happen for "q4" entries from temp-blockings 10767 $inx = 0; # dummy, to avoid warnings 10768 } 10769 $plot_one->($hop, $inx); 10770 } 10771 } else { 10772 # Plot symbol on every segment in the line 10773 for my $inx (0 .. $#kreuzungen-1) { 10774 $plot_one->(\@kreuzungen, $inx); 10775 } 10776 } 10777 } 10778 10779 if ($is_car && $car_photo && defined $icon_x) { 10780 $c->createImage($icon_x, $icon_y, 10781 -image => $car_photo, 10782 -anchor => $icon_anchor, 10783 -tags => [$abk, $sub_cat,$ret->[Strassen::NAME], $abk.'-'.$pos]); 10784 } 10785 } 10786 10787 if (($edit_mode || $edit_normal_mode || $args{FastUpdate}) and !$diffed_str) { 10788 warn "Try to copy original data" if $verbose; 10789 my $r = $complete_str->copy_orig; 10790 warn "Returned $r" if $verbose; 10791 } 10792 10793 }; 10794 warn $@ if $@; 10795 DecBusy($top); 10796 status_message(Mfmt("Layer <Sperrungen> gezeichnet"), "info"); 10797 Hooks::get_hooks("after_plot")->execute; 10798} 10799 10800sub _line_shorten { 10801 my($cref, $begin, $end) = @_; 10802 if (@$cref <= 2) { 10803 warn "Coordinate list too short for shortening either begin or end\n"; 10804 return; 10805 } 10806 if ($begin && $end && @$cref <= 4) { 10807 warn "Coordinate list too short for shortening begin and end (@$cref)\n"; 10808 return; 10809 } 10810 10811 if ($begin) { 10812 my $len1 = Strassen::Util::strecke([@{$cref}[0,1]], [@{$cref}[2,3]]); 10813 my $whole_len1 = $len1 > 20 ? 20 : $len1; 10814 @{$cref}[0,1] = 10815 (($cref->[0]-$cref->[2])/$len1*$whole_len1+$cref->[2], 10816 ($cref->[1]-$cref->[3])/$len1*$whole_len1+$cref->[3], 10817 ); 10818 } 10819 if ($end) { 10820 my $len2 = Strassen::Util::strecke([@{$cref}[-4,-3]], [@{$cref}[-2,-1]]); 10821 my $whole_len2 = $len2 > 20 ? 20 : $len2; 10822 @{$cref}[-2,-1] = 10823 (($cref->[-2]-$cref->[-4])/$len2*$whole_len2+$cref->[-4], 10824 ($cref->[-1]-$cref->[-3])/$len2*$whole_len2+$cref->[-3], 10825 ); 10826 } 10827} 10828 10829sub line_shorten_begin { _line_shorten(shift, 1, 0) } 10830sub line_shorten { _line_shorten(shift, 1, 1) } 10831sub line_shorten_end { _line_shorten(shift, 0, 1) } 10832 10833sub split_by_crossings { 10834 my @p = @_; 10835 return () if !@p; 10836 my $crossings = all_crossings(); 10837 my @ret = [$p[0]]; 10838 if (@p > 2) { 10839 for my $p_i (1 .. $#p-1) { 10840 my $p = $p[$p_i]; 10841 push @{ $ret[-1] }, $p; 10842 if (exists $crossings->{$p}) { 10843 push @ret, [$p]; 10844 } 10845 } 10846 } 10847 push @{ $ret[-1] }, $p[-1]; 10848 @ret; 10849} 10850 10851###################################################################### 10852# temp blockings 10853sub get_temp_blockings_files { 10854 my $temp_blockings_dir = "$datadir/temp_blockings"; 10855 my $file = "$temp_blockings_dir/bbbike-temp-blockings.pl"; 10856 my $optimized_file = "$temp_blockings_dir/bbbike-temp-blockings-optimized.pl"; 10857 return { dir => $temp_blockings_dir, 10858 file => $file, 10859 optimized_file => $optimized_file, 10860 }; 10861} 10862 10863sub activate_temp_blockings { 10864 my $do_show_active_temp_blockings = shift; 10865 my(%args) = @_; 10866 my $now = $args{-now} || time; 10867 my $from = $args{-from}; 10868 10869 my($temp_blockings_dir, $file, $optimized_file) = 10870 @{ get_temp_blockings_files() }{qw(dir file optimized_file)}; 10871 if (!-r $file && !-r $optimized_file) { 10872 status_message(M("Kein Support fuer temporaere Sperrungen, das Verzeichnis $temp_blockings_dir fehlt. Dieses Verzeichnis ist per git erh�ltlich, siehe README."), "warn"); 10873 return; 10874 } 10875 10876 # Use the optimized file? 10877 if (!-r $file) { 10878 $file = $optimized_file; 10879 } elsif (!defined $from || $from >= $now) { 10880 if (-r $optimized_file && -s $optimized_file && 10881 -M $optimized_file <= -M $file) { 10882 $file = $optimized_file; 10883 } 10884 } 10885 10886 if (!$do_show_active_temp_blockings) { 10887 $show_active_temp_blockings = 0; 10888 plot("p", "temp_sperre", -draw => 0); 10889 plot("str", "temp_sperre_s", -draw => 0); 10890 #XXX del? ??? not needed??? make_net(); # XXX find more performant solution 10891 #XXX del? undef $temporary_handicap_s; 10892 #if ($handicap_s_net) { 10893 # undef $handicap_s_net; 10894 # make_handicap_net(); 10895 #} 10896 undef $current_temp_blockings_net; 10897 undef $current_temp_blockings_ms; 10898 reset_temp_blockings(); 10899 hide_blockings(); 10900 hide_blockings_infobar(); 10901 return; 10902 } 10903 10904 eval { 10905 use vars qw(@temp_blocking); # XXX do not use a global such as this 10906 use vars qw(%temp_blocking_inx_mapping); # XXX dito 10907 @temp_blocking = (); 10908 do $file; # XXX Safe? 10909 my($file_mtime) = (stat($file))[9]; 10910 my @s; 10911 my $global_inx = -1; 10912 my $used_inx = -1; 10913 for my $o (@temp_blocking) { 10914 $global_inx++; 10915 next if !$o; # undefined entry 10916 my $do_it = 0; 10917 if (defined $from && (!defined $o->{until} || $o->{until} > $from)) { 10918 $do_it = 1; 10919 } 10920 if (!$do_it && ((!defined $o->{from} || $o->{from} < $now) && 10921 (!defined $o->{until} || $o->{until} > $now))) { 10922 $do_it = 1; 10923 } 10924 10925 if ($do_it) { 10926 require POSIX; 10927 my $datefmt = "%d.%m.%Y %H:%M:%S"; 10928 my $date_spec; 10929 { 10930 my $from_date_readable = defined $o->{from} ? POSIX::strftime($datefmt, localtime($o->{from})) : "..."; 10931 my $to_date_readable = defined $o->{until} ? POSIX::strftime($datefmt, localtime($o->{until})) : "..."; 10932 if ($from_date_readable eq '...' && $to_date_readable eq '...') { 10933 if ($o->{permanent} || $o->{recurring}) { 10934 $date_spec = M"periodische Sperrung"; 10935 } else { 10936 $date_spec = M"Ende unbekannt"; 10937 } 10938 } else { 10939 $date_spec = $from_date_readable . " - " . $to_date_readable; 10940 } 10941 } 10942 my $text = $o->{text} . " [" . $date_spec . "]"; 10943 my $s; 10944 my $f; 10945 my $mtime; 10946 if ($o->{file}) { 10947 $f = "$temp_blockings_dir/$o->{file}"; 10948 $s = Strassen->new($f); 10949 $mtime = $s->{Modtime}; 10950 } else { 10951 $s = Strassen->new_from_data_string($o->{data}); 10952 $mtime = $file_mtime; 10953 } 10954 my $new_s = Strassen->new; 10955 push @{$new_s->{DependentFiles}}, $f if $f; 10956 $s->init; 10957 while(1) { 10958 my $ret = $s->next; 10959 last if !@{ $ret->[Strassen::COORDS()] }; 10960 $ret->[Strassen::NAME] = $text; 10961 $new_s->push($ret); 10962 $new_s->set_directives_for_current({ info => [$o] }); 10963 $used_inx++; 10964 $temp_blocking_inx_mapping{$used_inx} = $global_inx; 10965 } 10966 $new_s->{Modtime} = $mtime; 10967 push @s, $new_s; 10968 } 10969 } 10970 if (!@s) { 10971 if ($verbose) { 10972 if (defined $args{-now}) { 10973 print STDERR "Keine aktuellen Sperrungen am " . scalar(localtime($now)) . "\n"; 10974 } else { 10975 print STDERR "Keine aktuellen Sperrungen\n"; 10976 } 10977 } 10978 return; 10979 } 10980 my $ms = MultiStrassen->new(@s); 10981 push @{ $ms->{DependentFiles} }, $file; 10982 if ($current_temp_blockings_ms && $current_temp_blockings_ms->shallow_compare($ms)) { 10983 warn "INFO: no change in temp blockings detected...\n"; 10984 } else { 10985 $current_temp_blockings_ms = $ms; 10986 $current_temp_blockings_net = StrassenNetz->new($ms); 10987 $current_temp_blockings_net->make_net_cat(-onewayhack => 1, -net2name => 1); 10988 $current_temp_blockings_net->make_sperre($ms, Type => ['wegfuehrung']); 10989 print STDERR "Aktuelle Sperrungen: " . join(", ", $ms->dependent_files) . "\n" if $verbose; 10990 add_temp_blockings_to_net(); 10991 plot("p", "temp_sperre", -object => $ms, -draw => 1); 10992 plot("str", "temp_sperre_s", -object => $ms, -draw => 1); 10993 if (@realcoords) { 10994 clear_undecided_temp_blockings(); 10995 check_path_in_blockings_net(\@realcoords); 10996 } 10997 } 10998 }; 10999 if ($@) { 11000 $show_active_temp_blockings = 0; 11001 status_message($@, "warn"); # do not die, may be called before mainloop 11002 } else { 11003 $show_active_temp_blockings = 1; 11004 } 11005} 11006 11007sub gui_activate_temp_blockings { 11008 if (!$show_active_temp_blockings) { 11009 $show_active_temp_blockings = 1; 11010 } 11011 activate_temp_blockings($show_active_temp_blockings); 11012} 11013 11014sub refresh_temp_blockings { 11015 if ($show_active_temp_blockings) { 11016 activate_temp_blockings($show_active_temp_blockings); 11017 } 11018} 11019 11020sub apply_temp_blockings { 11021 make_net() if !$net; 11022 add_temp_blockings_to_net(); 11023 re_search_gui(); 11024} 11025 11026sub add_temp_blockings_to_net { 11027 make_net() if !$net; 11028 make_handicap_net() if !$handicap_s_net; 11029 my $add_sperre_s = Strassen->new; 11030 my $add_handicap_s = Strassen->new; 11031 while(my($name,$v) = each %temp_blockings_on_route) { 11032 if ($v->{state} eq 'active') { 11033 for my $r (@{ $v->{data} }) { 11034 my $s; 11035 if ($r->[Strassen::CAT] =~ m{^q}) { 11036 $s = $add_handicap_s; 11037 } else { 11038 $s = $add_sperre_s; 11039 } 11040 $s->push($r); 11041 } 11042 } 11043 } 11044 11045 eval { # XXX check first if there's something to pop? 11046 $handicap_s_net->pop_stack; 11047 }; 11048 my $add_handicap_s_net = StrassenNetz->new($add_handicap_s); 11049 $add_handicap_s_net->make_net_cat; 11050 $handicap_s_net->push_stack($add_handicap_s_net); 11051 11052 $net->remove_all_from_deleted(undef, 'std-temp-blockings'); 11053 $net->make_sperre($add_sperre_s, Type => 'all', DelToken => 'std-temp-blockings'); 11054} 11055 11056 11057sub reset_temp_blockings { 11058 %temp_blockings_on_route = (); 11059 apply_temp_blockings(); 11060} 11061 11062sub _add_to_temp_blockings_on_route { 11063 my($r) = @_; 11064 my $blocking_text = $r->[Strassen::NAME]; 11065 if (!exists $temp_blockings_on_route{$blocking_text}) { 11066 # Gather all records belonging to this blocking: 11067 my @data; 11068 $current_temp_blockings_ms->init; 11069 while() { 11070 my $r = $current_temp_blockings_ms->next; 11071 my @c = @{ $r->[Strassen::COORDS] }; 11072 last if !@c; 11073 if ($r->[Strassen::NAME] eq $blocking_text) { 11074 push @data, $r; 11075 } 11076 } 11077 $temp_blockings_on_route{$blocking_text} = { state => 'undecided', 11078 data => \@data, 11079 }; 11080 } 11081} 11082 11083sub clear_undecided_temp_blockings { 11084 for my $name (keys %temp_blockings_on_route) { 11085 delete $temp_blockings_on_route{$name} 11086 if $temp_blockings_on_route{$name}->{state} eq 'undecided'; 11087 } 11088} 11089 11090sub check_path_in_blockings_net { 11091 return if !$current_temp_blockings_net; 11092 my($pathref) = @_; 11093 my $net = $current_temp_blockings_net->{Net}; 11094 my $wegfuehrung = $current_temp_blockings_net->{Wegfuehrung}; 11095 PATH_SEGMENT: for my $p_i (0 .. $#$pathref-1) { 11096 my($xy0, $xy1) = (join(',', @{$pathref->[$p_i]}), 11097 join(',', @{$pathref->[$p_i+1]})); 11098 11099 # Handling "1"/"2" and "qX" types 11100 if (exists $net->{$xy0} && exists $net->{$xy0}{$xy1}) { 11101 my($pos) = $current_temp_blockings_net->net2name($xy0, $xy1); 11102 if (defined $pos) { 11103 my $r = $current_temp_blockings_ms->get($pos); 11104 my $cat = $r->[Strassen::CAT]; 11105 if ($cat ne '3') { 11106 _add_to_temp_blockings_on_route($r); 11107 next PATH_SEGMENT; 11108 } 11109 # XXX else: Handled in the Wegf�hrung part 11110 } 11111 } 11112 11113 # Handling "3" (wegfuehrung) types 11114 if ($wegfuehrung && exists $wegfuehrung->{$xy1}) { 11115 for my $wegfuehrung (@{ $wegfuehrung->{$xy1} }) { 11116 CHECK_WEGFUEHRUNG: { 11117 for(my $j=0; $j<$#$wegfuehrung; $j++) { 11118 last CHECK_WEGFUEHRUNG 11119 if ($j > $p_i || join(",",@{$pathref->[$p_i-$j]}) ne $wegfuehrung->[$#$wegfuehrung-1-$j]); 11120 } 11121 # XXX Hackish: find a matching record in $current_temp_blockings_ms 11122 my $matching_r; 11123 $current_temp_blockings_ms->init; 11124 while() { 11125 my $r = $current_temp_blockings_ms->next; 11126 my @c = @{ $r->[Strassen::COORDS] }; 11127 last if !@c; 11128 for my $c_i (0 .. $#c-1) { 11129 if ($xy0 eq $c[$c_i] && $xy1 eq $c[$c_i+1]) { 11130 _add_to_temp_blockings_on_route($r); 11131 next PATH_SEGMENT; # XXX is this correct? or should we get all the wegf�hrung here? 11132 } 11133 } 11134 } 11135 } 11136 } 11137 } 11138 } 11139 11140 if (first { $temp_blockings_on_route{$_}->{state} eq 'undecided' } keys %temp_blockings_on_route) { 11141 show_blockings_infobar(); 11142 } else { 11143 hide_blockings_infobar(); 11144 } 11145 if (Tk::Exists($toplevel{temp_blockings})) { 11146 show_blockings(); 11147 } 11148} 11149 11150sub show_blockings { 11151 my $blockings_toplevel = redisplay_top($top, 'temp_blockings', 11152 -title => M"Aktuelle Sperrungen", 11153 ); 11154 my $toplevel_width = int($top->screenwidth*0.7); 11155 if (!defined $blockings_toplevel) { 11156 $blockings_toplevel = $toplevel{'temp_blockings'}; 11157 # XXX quick'n'dirty solution... better to keep all the widgets 11158 # and to just clear the items from the hlists. 11159 $_->destroy for ($blockings_toplevel->children); 11160 } else { 11161 $blockings_toplevel->geometry($toplevel_width."x200"); 11162 } 11163 11164 # packer priority -> draw first 11165 my $footer = $blockings_toplevel->Frame->pack(qw(-fill x -side bottom)); 11166 my $cb = $footer->Button(Name => "close", 11167 -command => sub { $blockings_toplevel->destroy })->pack(-anchor => 'e', -side => "right"); 11168 $blockings_toplevel->bind('<Escape>' => sub { $cb->invoke }); 11169 11170 11171 if (!keys %temp_blockings_on_route) { 11172 $blockings_toplevel->Label(-text => M"Keine Sperrungen auf der Route", -font => $font{bold})->pack; 11173 } else { 11174 my %gui_temp_blockings_on_route_active = map { ($_ => $temp_blockings_on_route{$_}->{state} eq 'active') } keys %temp_blockings_on_route; 11175 11176 require Tk::HList; 11177 my $hl; 11178 $hl = $blockings_toplevel->Scrolled 11179 ('HList', 11180 -columns => 3, 11181 -header => 1, 11182 -selectmode => 'single', 11183 -browsecmd => sub { 11184 my($hl_index) = @_; 11185 return if !defined $hl_index; 11186 my $name = $hl->info('data', $hl_index); 11187 return if !defined $name; 11188 my $coords = [ 11189 map { [ transpose_all(@{ Strassen::to_koord($_->[Strassen::COORDS]) }) ] } 11190 @{ $temp_blockings_on_route{$name}->{data} } 11191 ]; 11192 mark_street(-coords => $coords); 11193 }, 11194 -scrollbars => 'osoe', 11195 )->pack(qw(-fill both)); 11196 $hl->anchorClear; 11197 $hl->headerCreate(0, -text => M"Aktivieren"); 11198 $hl->headerCreate(1, -text => M"Sperrung"); 11199 $hl->headerCreate(2, -text => M"Warn-Zeitraum"); 11200 $hl->columnWidth(0, 80); 11201 my $descr_width = $toplevel_width - 200; 11202 $hl->columnWidth(1, $descr_width); 11203 11204 require Tk::ItemStyle; 11205 my(%header_style, %nopad_style, %descr_style, %text_style, %bg_color); 11206 for my $key (qw(odd even)) { 11207 my $bg_color = $key eq 'even' ? $hl->cget('-background') : '#dddddd'; 11208 $bg_color{$key} = $bg_color; 11209 $header_style{$key} = $hl->ItemStyle('text', -foreground => 'blue3', -font => $font{'bold'}, -background => $bg_color); 11210 $nopad_style{$key} = $hl->ItemStyle('window', -anchor => 'nw', -pady => 0, -padx => 0); # no -background available here 11211 $descr_style{$key} = $hl->ItemStyle('text', -wraplength => $descr_width-4, -anchor => 'nw', -background => $bg_color); 11212 $text_style{$key} = $hl->ItemStyle('text', -background => $bg_color); 11213 } 11214 11215 my %seen_temp_blockings_on_route; 11216 my $path_i = 0; 11217 11218 my $add_line = sub { 11219 my($name) = @_; 11220 my $key = $path_i % 2 == 0 ? 'even' : 'odd'; 11221 $hl->add($path_i, -itemtype => 'window', -style => $nopad_style{$key}, 11222 -widget => $hl->Checkbutton(-variable => \$gui_temp_blockings_on_route_active{$name}, 11223 -onvalue => 1, 11224 -offvalue => 0, 11225 -background => $bg_color{$key}, 11226 -highlightthickness => 0, 11227 ), 11228 -data => $name, 11229 ); 11230 if (my($desc, $date_spec) = $name =~ m{^(.*)\s\[(.*?)\]$}) { 11231 $hl->itemCreate($path_i, 1, -text => $desc, -style => $descr_style{$key}); 11232 $hl->itemCreate($path_i, 2, -text => $date_spec, -style => $text_style{$key}); 11233 } else { 11234 warn "Could not parse '$name'"; 11235 $hl->itemCreate($path_i, 1, -text => $name, -style => $descr_style{$key}); 11236 } 11237 $path_i++; 11238 }; 11239 11240 for my $name (sort keys %temp_blockings_on_route) { 11241 if ($temp_blockings_on_route{$name}->{state} eq 'undecided') { 11242 $add_line->($name); 11243 } 11244 } 11245 11246 my $not_used_header_shown; 11247 for my $name (sort keys %temp_blockings_on_route) { 11248 next if $temp_blockings_on_route{$name}->{state} eq 'undecided'; 11249 if (!$not_used_header_shown) { 11250 my $key = $path_i % 2 == 0 ? 'even' : 'odd'; 11251 $hl->add($path_i); 11252 $hl->itemCreate($path_i, 0, -style => $text_style{$key}); 11253 $hl->itemCreate($path_i, 1, -text => M"Bereits behandelte Sperrungen", -style => $header_style{$key}); 11254 $hl->itemCreate($path_i, 2, -style => $text_style{$key}); 11255 $path_i++; 11256 $not_used_header_shown++; 11257 } 11258 $add_line->($name); 11259 } 11260 11261 $footer->Button(-text => M"Ausgew�hlte umfahren", 11262 -command => sub { 11263 while(my($name,$v) = each %gui_temp_blockings_on_route_active) { 11264 $temp_blockings_on_route{$name}->{state} = $v ? 'active' : 'ignore'; 11265 } 11266 apply_temp_blockings(); 11267 })->pack(-anchor => 'w', -side => "left"); 11268 11269 $footer->Button(-text => M"Alle umfahren", 11270 -command => sub { 11271 while(my($name,$v) = each %temp_blockings_on_route) { 11272 $temp_blockings_on_route{$name}->{state} = 'active'; 11273 } 11274 apply_temp_blockings(); 11275 })->pack(-anchor => 'e', -side => "right"); 11276 $footer->Button(-text => M"Alle ignorieren", 11277 -command => sub { 11278 while(my($name,$v) = each %temp_blockings_on_route) { 11279 $temp_blockings_on_route{$name}->{state} = 'ignore'; 11280 } 11281 apply_temp_blockings(); 11282 })->pack(-anchor => 'e', -side => 'right'); 11283 } 11284} 11285 11286sub hide_blockings { 11287 if (Tk::Exists($toplevel{temp_blockings})) { 11288 $toplevel{temp_blockings}->destroy; 11289 } 11290} 11291 11292###################################################################### 11293### AutoLoad Sub 11294sub read_sperre_tragen { 11295 if (!eval { StrassenNetz::make_sperre_tragen(get_strassen_file($sperre_file), get_special_vehicle(), \%sperre_tragen, \%sperre_narrowpassage); 1 }) { 11296 warn $@; 11297 } 11298} 11299 11300# Liest aus der Datenbasis die Ampelinformation ein. 11301### AutoLoad Sub 11302sub read_ampeln { 11303 my($force) = @_; 11304 return if (!$force && keys %ampeln != 0); 11305 if (!eval { 11306 $p_obj{'lsa'} = new Strassen get_strassen_file($p_file{'lsa'}); 11307 %ampeln = %{ $p_obj{'lsa'}->get_hashref_by_cat }; 11308 1; 11309 }) { 11310 warn $@; 11311 %ampeln = (); 11312 } 11313} 11314 11315# Liest aus der Datenbasis die H�heninformation ein. 11316### AutoLoad Sub 11317sub read_hoehe { 11318 my(%args) = @_; 11319 return if (!$args{-force} && keys %hoehe != 0 && 11320 $p_obj{"hoehe"} && $p_obj{"hoehe"}->is_current); 11321 if (!eval { 11322 my $h = new Strassen ($args{-file} 11323 ? $args{-file} 11324 : get_strassen_file("hoehe") 11325 ); 11326 %hoehe = %{ $h->get_hashref }; 11327 $p_obj{"hoehe"} = $h; 11328 1; 11329 }) { 11330 warn $@; 11331 %hoehe = (); 11332 } 11333} 11334 11335# Zeichnet die H�hendaten. 11336### AutoLoad Sub 11337sub plot_hoehe { 11338 my(%args) = @_; 11339 Hooks::get_hooks("before_plot")->execute; 11340 $c->delete('hoehe'); 11341 if ($p_draw{'hoehe'}) { 11342 my $coordsys = $coord_system_obj->coordsys; 11343 IncBusy($top); 11344 eval { 11345 read_hoehe(%args); 11346 while(my($koord,$hoehe) = each %hoehe) { 11347 my($xx,$yy) = split(/,/, $koord); 11348 if ($edit_mode && $xx =~ /([A-Za-z])?(-?\d+)$/) { 11349 my $this_coordsys = (defined $1 ? $1 : ''); 11350 if ($this_coordsys eq $coordsys || 11351 !($this_coordsys ne '' || $coordsys ne 'B')) { 11352 $xx = $2; 11353 } else { 11354 next; # while 11355 } 11356 } 11357 my($x, $y) = transpose($xx, $yy); 11358 $c->createLine($x, $y, $x+1, $y+1, 11359 -fill => 'red', 11360 -tags => 'hoehe', 11361 ); 11362 $c->createText($x+1, $y+1, -anchor => 'nw', 11363 -font => $font{'small'}, 11364 -text => $hoehe, 11365 -tags => 'hoehe', 11366 ); 11367 } 11368 }; 11369 warn __LINE__ . ": $@" if $@; 11370 DecBusy($top); 11371 } 11372 Hooks::get_hooks("after_plot")->execute; 11373} 11374 11375# XXX Folgende drei Funktionen zusammenfassen 11376# Gibt ein Gew�sser-Objekt zur�ck. 11377### AutoLoad Sub 11378sub _get_wasser_obj { 11379 my $filename = shift; 11380 my @obj; 11381 if ($wasserstadt) { 11382 push @obj, Strassen->new($filename); 11383 } 11384 if ($wasserumland) { 11385 push @obj, Strassen->new(get_strassen_file("wasserumland")); 11386 } 11387 if ($str_far_away{'w'}) { 11388 push @obj, Strassen->new(get_strassen_file("wasserumland2")); 11389 } 11390 return if !@obj; 11391 return $obj[0] if (@obj == 1); 11392 new MultiStrassen @obj; 11393} 11394 11395# Gibt ein Orte-Objekt zur�ck. 11396### AutoLoad Sub 11397sub _get_orte_obj { 11398 my $type = shift || "o"; 11399 my $fname = ($type eq 'oo' ? 'orte_city' : 'orte'); 11400 my @obj; 11401 push @obj, new Strassen get_strassen_file($fname); 11402 if ($p_far_away{$type}) { 11403 push @obj, new Strassen get_strassen_file($fname . "2"); 11404 } 11405 return $obj[0] if (@obj == 1); 11406 new MultiStrassen @obj; 11407} 11408 11409# Gibt ein Landstra�en-Objekt zur�ck. 11410### AutoLoad Sub 11411sub _get_landstr_obj { 11412 my @obj; 11413 push @obj, new Strassen get_strassen_file($str_file{'l'}); 11414 if ($str_far_away{'l'}) { 11415 my $file = "landstrassen2"; 11416 push @obj, new Strassen get_strassen_file($file); 11417 } 11418 if ($str_regions{'l'}) { 11419 foreach my $file (@{ $str_regions{'l'} }) { 11420 push @obj, new Strassen get_strassen_file($file); 11421 } 11422 } 11423 return $obj[0] if (@obj == 1); 11424 new MultiStrassen @obj; 11425} 11426 11427# Gibt ein F�hren-Objekt zur�ck. 11428### AutoLoad Sub 11429sub _get_ferry_obj { 11430 my @obj; 11431 push @obj, Strassen->new(get_strassen_file($str_file{'e'})); 11432 push @obj, eval { Strassen->new(get_strassen_file($str_file{'comm-ferry'})) }; 11433 warn $@ if $@; 11434 return $obj[0] if (@obj == 1); 11435 MultiStrassen->new(@obj); 11436} 11437 11438# Gibt ein Kommentar-Objekt zur�ck. 11439### AutoLoad Sub 11440sub _get_comments_obj { 11441 my @objs; 11442 for my $type (@comments_types) { 11443 next if $type eq "mount"; 11444 eval { 11445 my $f = get_strassen_file("comments_$type"); 11446 push @objs, Strassen->new($f); 11447 }; warn $@ if $@; 11448 } 11449 MultiStrassen->new(@objs); 11450} 11451 11452# Gibt ein Fragezeichen-Objekt zur�ck. 11453### AutoLoad Sub 11454sub _get_fragezeichen_obj { 11455 my @files; 11456 push @files, get_strassen_file("fragezeichen"); 11457##XXX hmmm. When editing, I don't want to see the non-orig fragezeichen. 11458##XXX But sometimes I like to... need to gather wisdom 11459# if ($files[0] ne 'fragezeichen') { # happens in edit mode 11460# push @files, "fragezeichen"; 11461# } 11462 my $xxx_file = catfile($FindBin::RealBin, "tmp", "XXX.bbd"); 11463 if (0 && -r $xxx_file) { # XXX soll ich oder soll ich nicht XXX.bbd mit einbinden? 11464 push @files, $xxx_file; 11465 } 11466 if (@files > 1) { 11467 MultiStrassen->new(@files); 11468 } else { 11469 Strassen->new($files[0]); 11470 } 11471} 11472 11473# Zeichnet Punkte auf dem Canvas. 11474# plotp ist nur ein Dispatcher. 11475### AutoLoad Sub 11476sub plotp { 11477 my($abk, %args) = @_; 11478 return if $abk =~ /^pp/; # wird in plotstr gezeichnet 11479 return if !$c; 11480 if ($abk eq 'p') { 11481 require BBBikeAdvanced; 11482 ploths(); 11483 } elsif ($abk eq 'o') { 11484 plotorte(Shortname => 1, %args); 11485 } elsif ($abk eq 'obst') { 11486 plotobst(); 11487 } elsif ($abk eq 'hoehe') { 11488 plot_hoehe(); 11489 } else { 11490 plot_point($abk, %args); 11491 } 11492} 11493 11494# Konfiguriert Punktsymbole, z.B. U-Bahn-Zeichen 11495### AutoLoad Sub 11496sub config_symbol { 11497 my($c, $abk, %args) = @_; 11498 my $tag_bg = $args{'-tag_bg'} || "$abk-bg"; 11499 my $tag_fg = $args{'-tag_fg'} || "$abk-fg"; 11500 my $tag_label = $args{'-tag_label'} || "$abk-label"; 11501 if ($XXX_use_old_R_symbol && $abk eq 'r') { 11502 my %arg = get_symbol_scale('r'); 11503 while(my($cat,$v) = each %{ $str_restrict{'r'} }) { 11504 $c->itemconfigure 11505 ("$abk-$cat-bg", 11506 -fill => ($cat =~ m{^R[ABC]$} ? $category_color{'R'} : $category_color{$cat}), 11507 -capstyle => $capstyle_round, 11508 -width => $arg{-width}, 11509 ); 11510 } 11511 $c->itemconfigure 11512 ($tag_fg, -anchor => 'c', -fill => 'white', 11513 -text => (defined $arg{-font} 11514 ? ($abk eq 'b' ? 'S' : 'R') : ''), 11515 (defined $arg{-font} ? (-font => $arg{-font}) : ()), 11516 ); 11517 $c->itemconfigure($tag_label, -font => "$sans_serif_font_family -12"); 11518 change_label_visibility($c, undef, undef, ["r-label"]); 11519 } elsif ($abk =~ /^[ubr]$/) { 11520 $c->itemconfigure($tag_fg, -image => get_symbol_scale($abk)); 11521 if ($abk eq 'u') { 11522 $c->itemconfigure('u-U0-fg', -image => get_symbol_scale('u-U0')); 11523 $c->itemconfigure('u-UBau-fg', -image => get_symbol_scale('u-UBau')); 11524 } elsif ($abk eq 'b') { 11525 $c->itemconfigure('b-S0-fg', -image => get_symbol_scale('b-S0')); 11526 $c->itemconfigure('b-SBau-fg', -image => get_symbol_scale('b-SBau')); 11527 } elsif ($abk eq 'r') { 11528 $c->itemconfigure('r-R0-fg', -image => get_symbol_scale('r-R0')); 11529 $c->itemconfigure('r-RBau-fg', -image => get_symbol_scale('r-RBau')); 11530 $c->itemconfigure('r-RP-fg', -image => get_symbol_scale('r-RP')); 11531 } 11532 $c->itemconfigure($tag_label, -font => "$sans_serif_font_family -12"); 11533 change_label_visibility($c, undef, undef, ["$abk-label"]); 11534 } elsif ($abk =~ /^L\d+/) { 11535 eval { 11536 $c->itemconfigure($tag_fg, 11537 -capstyle => $capstyle_round, 11538 ); 11539 }; warn $@ if $@; 11540 } elsif ($abk eq 'pl') { 11541 $c->itemconfigure($tag_fg, -fill => 'red', -capstyle => 'projecting', 11542 -width => 8); 11543 } elsif ($abk eq 'vf') { 11544 for my $cat (qw(Vf Kz)) { 11545 $c->itemconfigure("$abk-$cat-fg", -image => get_symbol_scale("$abk-$cat")); 11546 } 11547 $c->itemconfigure($tag_bg, -fill => 'black', 11548 -width => 3); # XXX width skalierbar machen 11549 } elsif ($abk =~ /^(kn|rest)$/) { 11550 $c->itemconfigure($tag_fg, -image => get_symbol_scale($abk)); 11551 } elsif ($abk eq 'ki') { 11552 $c->itemconfigure($tag_fg, -image => $kino_klein_photo); 11553 } 11554} 11555 11556# Zeichnen von Punkten. Hiermit werden U-/S-/R-Bahnh�fe, Ampeln und alle 11557# sonstigen Punkte gezeichnet. 11558# Arguments: 11559# $abk: layer token 11560# -filename => $filename (Alias: Filename => $filename) 11561# NameDraw => $boolean 11562### AutoLoad Sub 11563sub plot_point { 11564 my($abk, %args) = @_; 11565 11566 status_message(""); 11567 11568 # Tags l�schen 11569 my @del_tags = ("$abk-bg", "$abk-img", "$abk-fg", "$abk-label"); 11570 11571 if (!$args{FastUpdate}) { 11572 $c->delete($_) for (@del_tags); 11573 } 11574 11575 my($ampel_photo, $ampelf_photo, $andreaskr_photo, $andreaskr_grey_photo, $zugbruecke_photo); 11576 if ($abk eq 'lsa') { 11577 $ampel_photo = get_symbol_scale('lsa-X'); 11578 $ampelf_photo = get_symbol_scale('lsa-F'); 11579 $andreaskr_photo = get_symbol_scale('lsa-B'); 11580 $andreaskr_grey_photo = get_symbol_scale('lsa-B0'); 11581 $zugbruecke_photo = get_symbol_scale('lsa-Zbr'); 11582 $c->delete('lsas'); # Ampelschaltung-Symbole l�schen 11583 $c->delete('lsas-t'); # Ampelschaltung-Symbole l�schen 11584 } 11585 if (!$p_draw{$abk}) { 11586 if ($main::lazy_p{$abk}) { 11587 bbbikelazy_remove_data("p", $abk); 11588 } 11589 status_message(Mfmt("Layer <%s> entfernt", exists $p_attrib{$abk} ? $p_attrib{$abk}->[ATTRIB_PLURAL] : $abk), "info"); 11590 return; 11591 } 11592 11593 my $filename = $args{-filename} || $args{Filename}; 11594 my $filename_maybe; 11595 if (!defined $filename) { 11596 $filename = get_strassen_file($p_file{$abk}); 11597 $filename_maybe = $p_file{$abk} if $edit_mode_flag; 11598 } 11599 if (!defined $filename) { 11600 status_message("Filename is not defined", 'err'); 11601 return; 11602 } 11603 11604 my $lazy = defined $args{-lazy} ? $args{-lazy} : $lazy_plot; 11605 if ($lazy && !$args{FastUpdate}) { 11606 status_message(Mfmt("Layer <%s> gezeichnet", exists $p_attrib{$abk} ? $p_attrib{$abk}->[ATTRIB_PLURAL] : $abk), "info"); 11607 return bbbikelazy_add_data("p", $abk, $filename, {exists $args{NameDraw} ? (NameDraw => $args{NameDraw}) : ()}); 11608 } 11609 11610 # XXX die anderen R�ckgabewerte (..._list, $ignore) werden noch ignoriert 11611 my($restrict) = _set_restrict($abk); 11612 11613 my $default_width; 11614 if (defined $args{Width}) { $default_width = $args{Width} } 11615 11616 my $coordsys = $coord_system_obj->coordsys; 11617 11618 destroy_delayed_restack(); 11619 11620 IncBusy($top); 11621 $progress->Init(-dependents => $c, 11622 (defined $filename ? (-label => $filename) : ()), 11623 ); 11624 11625 eval { 11626 my $bhf; 11627 if ($args{FastUpdate} || 11628 (defined $p_obj{$abk} && 11629 $p_obj{$abk}->is_current && 11630 $coord_system eq 'standard' && 11631 $abk !~ /^L\d+/) 11632 ) { 11633 $bhf = $p_obj{$abk}; 11634 } else { 11635 cache_decider_init(); 11636 eval { 11637 $bhf = new Strassen $filename; 11638 }; 11639 if ($@ && $filename_maybe) { 11640 eval { 11641 $bhf = Strassen->new($filename_maybe); 11642 }; 11643 } 11644 if ($@) { 11645 $p_draw{$abk} = 0; 11646 die "OK" if ($abk eq 'r' && $coord_system ne 'standard'); 11647 die "no-original-datadir" if $no_original_datadir; 11648 die $@; 11649 } 11650 if (($coord_system eq 'standard' && 11651 (cache_decider() || $abk =~ /^L\d+/ || $abk eq 'kn') # 'L...' und 'kn' wegen Info 11652 ) || 11653 $edit_normal_mode # Always cache in edit mode to make "reload all" work 11654 ) { 11655 $p_obj{$abk} = $bhf; 11656 } 11657 } 11658 11659 handle_global_directives($bhf, $abk); 11660 # XXX obsolete: 11661 if (-e "$filename.desc") { 11662 require BBBikeAdvanced; 11663 read_desc_file("$filename.desc", $abk); 11664 } 11665 11666 my $complete_str = $bhf; 11667 my $diffed_str = 0; 11668 my $indexmap; 11669 if ($args{FastUpdate}) { 11670 my($new_str, $todelref); 11671 ($new_str, $todelref, $indexmap) = $bhf->diff_orig(-clonefile => 1); 11672 if (!defined $new_str) { 11673 print STDERR M("Diff-Ausgabe wird nicht verwendet") if $verbose; 11674 $c->delete($_) for (@del_tags); 11675 } else { 11676 if ($verbose) { 11677 print STDERR M("Diff-Ausgabe wird verwendet"), "\n"; 11678 print STDERR Mfmt("Anzahl der neu zu zeichnenden Punkte: %d", scalar @{$new_str->data}), "\n"; 11679 print STDERR Mfmt("Anzahl der zu l�schenden Punkte: %d", scalar @$todelref), "\n"; 11680 } 11681 foreach my $id (@$todelref) { 11682 for my $ptagadd ("") { # XXX what's necessary of the following?, "-fg", "-bg", "-img", "-label") { 11683 $c->delete("$abk$ptagadd-$id"); 11684 } 11685 } 11686 $bhf = $new_str; 11687 $diffed_str = 1; 11688 } 11689 } 11690 11691 my %conv_args; 11692 if ($args{-map}) { 11693 $conv_args{Map} = $args{-map}; 11694 } 11695 my $conv = $bhf->get_conversion(%conv_args); 11696 11697 # XXX Experiment!!! 11698 if ($orientation eq 'landscape' && 11699 !$edit_mode && 11700#XXX? !$edit_normal_mode && 11701 $abk eq 'lsa' && 11702 !$diffed_str && 11703 !$conv && 11704 defined &BBBike::fast_plot_point) { 11705 eval { 11706 die if $bhf->isa("Strassen::Storable"); 11707 my(@files) = $bhf->file; 11708 if (grep { /\.gz$/ } @files) { 11709 die "fast_plot_point can't handle gzipped files yet"; 11710 } 11711 my(@args) = ($c, $abk, 11712 (@files > 1 ? \@files : @files), 11713 $progress); 11714 BBBike::fast_plot_point(@args); 11715 }; 11716 my $err = $@; 11717 if (!$err) { 11718 %ampeln = %{ $bhf->get_hashref_by_cat }; 11719 goto PLOTPOINT_CONT; 11720 } else { 11721 warn $err if $^W; 11722 } 11723 } 11724 11725 my $real_i = 0; 11726 my $i; 11727 my $anzahl_eindeutig = $bhf->count; 11728 $bhf->init; 11729 # XXX Duplikat in BBBikeLazy: 11730 my $rbahn_length = ($abk eq 'r' 11731 ? do { my(%a) = get_symbol_scale('r'); 11732 $a{-width}/2 } 11733 : 0); 11734 my $name_draw = (exists $args{NameDraw} 11735 ? $args{NameDraw} : $p_name_draw{$abk}); 11736 my $name_draw_tag = "$abk-label"; 11737 my $name_draw_other = ($name_draw_tag =~ /^[ubr]-label$/ 11738 ? [qw(u-label b-label r-label)] 11739 : $name_draw_tag); 11740 my $no_overlap_label = (exists $args{NoOverlapLabel} 11741 ? $args{NoOverlapLabel} : $no_overlap_label{$abk}); 11742 my $xadd_anchor = $xadd_anchor_type->{'u'}; 11743 my $yadd_anchor = $yadd_anchor_type->{'u'}; 11744 my $label_spaceadd = $label_spaceadd{'u'}; 11745 11746 my $draw_sub = eval $plotpoint_draw_sub; 11747 string_eval_die($@, $plotpoint_draw_sub) if $@; 11748 11749 while(1) { 11750 my $ret = $bhf->next; 11751 last if !@{$ret->[Strassen::COORDS]}; 11752 $progress->Update($real_i/$anzahl_eindeutig) if $real_i % 80 == 0; 11753 $i = $indexmap && exists $indexmap->{$real_i} ? $indexmap->{$real_i} : $real_i; 11754 $draw_sub->($ret); 11755 $real_i++; 11756 } 11757 config_symbol($c, $abk); 11758 PLOTPOINT_CONT: 11759 11760 if (($edit_mode || $edit_normal_mode || $abk eq 'relgps' || $args{FastUpdate})) { # XXX? and !$diffed_str) { 11761 warn "Try to copy original data" if $verbose; 11762 my $r = $complete_str->copy_orig; 11763 warn "Returned $r" if $verbose; 11764 } 11765 11766 restack_delayed(); # XXX check! 11767 }; 11768 if ($@) { 11769 if ($@ =~ /^no-original-datadir/) { 11770 # silently ignore 11771 } elsif ($@ !~ /^OK/) { 11772 status_message($@, ($edit_mode || $edit_normal_mode ? 'info-stack-trace' : 'err')); 11773 } 11774 } 11775 $progress->Finish; 11776 DecBusy($top); 11777} 11778 11779# Gibt einen eindeutigen Bezeichner f�r das Caching der Orts/Stra�enlisten 11780# zur�ck. 11781### AutoLoad Sub 11782sub get_cache_identifier { 11783 my($linetype, $type) = @_; 11784 if ($linetype eq 'p') { 11785 my $fa = $p_far_away{$type} || ''; 11786 $fa; 11787 } elsif ($linetype eq 's' || $linetype eq 'str') { # XXX 'str' is probably wrong... 11788 my $fa = $str_far_away{$type} || ''; 11789 # XXX str_regions? 11790 my $ret = $fa; 11791 if ($type eq 'w') { 11792 $ret .= "-$wasserstadt-$wasserumland"; 11793 } 11794 $ret; 11795 } else { 11796 die "Unknown linetype: $linetype"; 11797 } 11798} 11799 11800# Dialog zum Ausw�hlen einer Stra�e oder eines Ortes. 11801### AutoLoad Sub 11802sub choose_ort { 11803 my($linetype, $type, %args) = @_; 11804 11805 my $data = $args{-data}; 11806 my $nodraw = $args{-nodraw}; 11807 my $ondestroy = $args{-ondestroy}; 11808 my $additionalframe = $args{-additionalframe}; 11809 my $sorted = "auto"; 11810 if (exists $args{-unsorted}) { 11811 $sorted = "unsorted"; 11812 } 11813 my $splitter = $args{-splitter}; 11814 my $columnwidths = $args{-columnwidths}; 11815 my $container = $args{-container}; 11816 my $do_popup = exists $args{-popup} ? $args{-popup} : 1; 11817 my $see = $args{-see}; 11818 11819 unless ($nodraw) { 11820 if ($linetype =~ /^s/) { 11821 if (!$str_draw{$type}) { 11822 $str_draw{$type} = 1; 11823 plot('str',$type); 11824 } 11825 } elsif ($linetype =~ /^p/) { 11826 if (!$p_draw{$type}) { 11827 $p_draw{$type} = 1; 11828 plot('p',$type); 11829 } 11830 } else { 11831 die "Unknown linetype: $linetype"; 11832 } 11833 } 11834 11835 my $action = (exists $args{'-action'} 11836 ? $args{'-action'} 11837 : ($linetype =~ /^s/ 11838 ? \&mark_street 11839 : ($linetype =~ /^p/ 11840 ? \&mark_point 11841 : die "Unknown linetype: $linetype" 11842 ) 11843 ) 11844 ); 11845 11846 if (!$args{-rebuild}) { 11847 if (!defined $choose_ort_cache{"$linetype-$type"} or 11848 get_cache_identifier($linetype, $type) 11849 ne $choose_ort_cache{"$linetype-$type"}) { 11850 $args{-rebuild} = 1; 11851 } 11852 } 11853 11854 my $lb; 11855 11856 if (!$toplevel{"chooseort-$type-$linetype"} or 11857 !Tk::Exists($toplevel{"chooseort-$type-$linetype"}) or 11858 $args{'-rebuild'} or 11859 $container) { 11860 if (defined $toplevel{"chooseort-$type-$linetype"} and 11861 Tk::Exists($toplevel{"chooseort-$type-$linetype"})) { 11862 $toplevel{"chooseort-$type-$linetype"}->destroy; 11863 delete $toplevel{"chooseort-$type-$linetype"}; 11864 } 11865 11866 my $attrib = ($linetype eq 's' 11867 ? $str_attrib{$type} 11868 : $p_attrib{$type}); 11869 11870 IncBusy($top); 11871 my $t; 11872 eval { 11873 my %orte; 11874 my @orte; 11875 my $object; 11876 my $conv; 11877 my $title = $attrib ? $attrib->[ATTRIB_PLURAL] : undef; 11878 if ($linetype =~ /^p/) { 11879 if ($data) { 11880 $object = $data; 11881 } elsif (defined $p_obj{$type} && $coord_system eq 'standard') { 11882 $object = $p_obj{$type}; 11883 } else { 11884 cache_decider_init(); 11885 if ($type eq 'o') { 11886 $object = _get_orte_obj("o"); 11887 } else { 11888 $object = get_strassen_obj($p_file{$type}); 11889 } 11890 if ($coord_system eq 'standard' && cache_decider()) { 11891 $p_obj{$type} = $object; 11892 } 11893 } 11894 11895 my $i = 0; 11896 $object->init; 11897 while(1) { 11898 my $ret = $object->next; 11899 last if @{$ret->[Strassen::COORDS]} == 0; 11900 my $strname = $ret->[Strassen::NAME]; 11901 $strname =~ s/\|/ /g; # Bla|Foo: Pipe-Zeichen entfernen 11902 $orte{$strname} = $i; 11903 $i++; 11904 push @orte, $strname; 11905 } 11906 } elsif ($linetype =~ /^s/) { 11907 if ($data) { 11908 $object = $data; 11909 } elsif (defined $str_obj{$type} && $coord_system eq 'standard') { 11910 $object = $str_obj{$type}; 11911 } else { 11912 cache_decider_init(); 11913 $object = get_any_strassen_obj("str", $type); 11914 if ($coord_system eq 'standard' && cache_decider()) { 11915 $str_obj{$type} = $object; 11916 } 11917 } 11918 11919 my $i = 0; 11920 $object->init; 11921 while(1) { 11922 my $ret = $object->next; 11923 last if @{$ret->[Strassen::COORDS]} == 0; 11924 my $strname = $ret->[Strassen::NAME]; 11925 $strname =~ s/\|/ /g; # Bla|Foo: Pipe-Zeichen entfernen 11926 my @strname; 11927 if ($attrib->[ATTRIB_LINES]) { # Linien? 11928 @strname = split(/,/, $strname); 11929 } else { 11930 @strname = ($strname); 11931 } 11932 foreach $strname (@strname) { 11933 if (exists $orte{$strname}) { 11934 $orte{$strname} .= ",$i"; 11935 } else { 11936 $orte{$strname} = $i; 11937 } 11938 push @orte, $strname; 11939 } 11940 $i++; 11941 } 11942 } 11943 11944 if ($sorted eq 'auto') { 11945 if ($object && $object->can("get_global_directive")) { 11946 my $listing_sort = $object->get_global_directive("listing_sort"); 11947 if ($listing_sort && $listing_sort =~ m{^(unsorted|natural)$}) { 11948 $sorted = $1; 11949 } 11950 } 11951 } 11952 if ($sorted eq 'auto') { 11953 $sorted = "alphabetic"; 11954 } 11955 if ($sorted eq 'natural') { 11956 if (!eval { require Sort::Naturally; 1 }) { 11957 status_message(M"Sort::Naturally kann nicht geladen werden, nat�rliches Sortieren ist nicht m�glich.", "info"); 11958 $sorted = "alphabetic"; 11959 } 11960 } 11961 11962 if (!defined $title && $object && $object->can("get_global_directive")) { 11963 $title = $object->get_global_directive("title.$Msg::lang"); 11964 if (!defined $title) { 11965 $title = $object->get_global_directive("title"); 11966 if (!defined $title) { 11967 if (defined $object->file) { 11968 $title = basename($object->file); 11969 } 11970 if (!defined $title) { 11971 $title = "Layer $linetype/$type"; 11972 } 11973 } 11974 } 11975 } 11976 11977 $conv = $object && $object->get_conversion; 11978 11979 my $Listbox = "Listbox"; 11980 if ($splitter) { 11981 $Listbox = "HList"; 11982 } else { 11983 if ($sorted eq 'alphabetic') { 11984 if (!defined $K2Listbox) { 11985 TRYLISTBOX: { 11986 foreach my $try (qw(K2Listbox KListbox WListbox)) { 11987 if (eval q{ require Tk::} . $try . q{; 1;} && !$@) { 11988 $K2Listbox = $Listbox = $try; 11989 last TRYLISTBOX; 11990 } else { 11991 warn "Can't use module Tk::$try: $@"; 11992 } 11993 } 11994 } 11995 } else { 11996 $Listbox = $K2Listbox; 11997 } 11998 } 11999 } 12000 12001 if ($container) { 12002 $t = $container; 12003 } else { 12004 $t = $top->Toplevel(-title => $title, 12005 -class => "Bbbike Chooser"); 12006 set_as_toolwindow($t); 12007 if ($coord_system eq 'standard') { 12008 if ($ondestroy) { 12009 $t->protocol('WM_DELETE_WINDOW', [$ondestroy, $t]); 12010 } else { 12011 $t->protocol('WM_DELETE_WINDOW', sub { $t->withdraw }); 12012 } 12013 $toplevel{"chooseort-$type-$linetype"} = $t; 12014 } 12015 } 12016 my($showb, $closeb); 12017 12018 my $f = $t->Frame->pack(-side => "bottom"); # Button-Frame 12019 12020 if ($args{'-completelistbutton'}) { 12021 my $ff = $t->Frame->pack(-side => "bottom"); 12022 my $label = $args{'completelistbuttonlabel'} || M"Komplette Liste"; 12023 $ff->Button(-text => $label, 12024 -command => $args{'-completelistbutton'}, 12025 )->pack; 12026 } 12027 if ($additionalframe) { 12028 my $ff = $t->Frame->pack(-side => "bottom", -fill => "both"); 12029 $additionalframe->($t, $ff); 12030 } 12031 12032 my $markf; 12033 if ($args{'-markstartifactive'}) { 12034 if (($linetype eq 's' && $type =~ /^[sl]$/ && 12035 $net_type eq 's') || 12036 ($linetype eq 'p' && $type =~ /^[ub]$/ && 12037 $net_type eq 'us') || 12038 ($linetype eq 'p' && $type =~ /^[ubr]$/ && 12039 $net_type eq 'rus') || 12040 ($linetype eq 'p' && $type eq 'r' && 12041 $net_type eq 'r') || 12042 ($linetype eq 's' && $type =~ /^wr/ && 12043 $net_type eq 'wr') 12044 ) { 12045 $args{-markstart} = 1; 12046 } 12047 } 12048 12049 if ($args{'-markstart'}) { 12050 $markf = $t->Frame->pack(-side => "bottom"); 12051 } 12052 12053 my $max_cols; 12054 if ($Listbox =~ /K.*Listbox/ && $Tk::VERSION >= 800) { 12055 my $c = $t->Canvas(-takefocus => 0)->pack; 12056 my $x = 2; # 2, otherwise A may be cropped with some fonts 12057 for ('A'..'Z') { 12058 $c->createText($x, 1, 12059 -text => $_, 12060 -font => $font{'small'}, 12061 -anchor => 'nw', 12062 -tags => $_, 12063 -fill => 'black', 12064 ); 12065 $x += $t->fontMeasure($font{'small'}, $_); 12066 } 12067 $x+=2; # otherwise Z may be cropped 12068 my $asc = $t->fontMetrics($font{'small'}, '-ascent'); 12069 my $des = $t->fontMetrics($font{'small'}, '-descent'); 12070 # Note that this Canvas is NOT adjusted if the font 12071 # is changed at runtime. 12072 $c->GeometryRequest($x, $asc+$des+2); 12073 $c->bind('all', '<ButtonPress-1>' => sub { 12074 my(@c) = $c->gettags('current'); 12075 $lb->Goto($c[0]); 12076 }); 12077 $c->bind('all', '<Enter>' => sub { 12078 $c->itemconfigure('current', -fill => 'red'); 12079 }); 12080 $c->bind('all', '<Leave>' => sub { 12081 $c->itemconfigure('current', -fill => 'black'); 12082 }); 12083 } 12084 12085 if ($splitter) { 12086 keys %orte; # reset 12087 my($first_ort, $first_index) = each %orte; 12088 keys %orte; # reset 12089 my(@cols) = $splitter->($first_ort, $first_index); 12090 $max_cols = scalar @cols; 12091 } 12092 12093 $lb = $t->Scrolled($Listbox, 12094 -scrollbars => 'osoe', 12095 -selectmode => 'single', 12096 ($splitter 12097 ? (-columns => $max_cols, 12098 -exportselection => 1, 12099 ) 12100 : () 12101 ), 12102 )->pack(-expand => 1, -fill => 'both'); 12103 $t->Advertise(Listbox => $lb->Subwidget("scrolled")); 12104 12105 if ($splitter) { 12106 my @wraplength; 12107 if ($columnwidths) { 12108 @wraplength = @$columnwidths; 12109 } else { 12110 my $wraplength = $max_cols > 1 ? int($top->screenwidth/($max_cols)) : $top->screenwidth; 12111 @wraplength = ($wraplength) x $max_cols; 12112 } 12113 my @text_style; 12114 require Tk::ItemStyle; 12115 for my $col (0 .. $max_cols-1) { 12116 push @text_style, $lb->ItemStyle('text', -wraplength => $wraplength[$col] || 100); 12117 } 12118 my $inx = 0; 12119 # XXX no support for sort styles here XXX 12120 for my $ort (sort keys %orte) { 12121 my(@cols) = $splitter->($ort, $orte{$ort}); 12122 $lb->add($inx, 12123 -text => $cols[0], 12124 -data => $ort, 12125 -style => $text_style[0], 12126 ); 12127 for my $col (1 .. $#cols) { 12128 next if $col > $max_cols; # XXX off by one? 12129 $lb->itemCreate($inx, $col, 12130 -text => $cols[$col], 12131 -style => $text_style[$col], 12132 ); 12133 } 12134 $inx++; 12135 } 12136 # XXX destroy text_styles? 12137 } else { 12138 if ($sorted eq 'unsorted') { 12139 $lb->insert('end', 12140 @orte); 12141 } elsif ($sorted eq 'natural') { 12142 $lb->insert('end', 12143 Sort::Naturally::nsort(keys %orte)); 12144 } else { 12145 # XXX use Sort::Naturally if $sorted eq 'natural' 12146 # "use locale" is not used here because: 12147 # - there's maybe no locale support at all 12148 # - the german locale may be missing 12149 # - with various perl versions and OSes I had in the 12150 # past problems with "use locale" 12151 my $tf_sub = \&BBBikeUtil::umlauts_for_german_locale; 12152 $lb->insert('end', 12153 map { $_->[1] } 12154 sort { $a->[0] cmp $b->[0] } 12155 map { [ do { /^\(?(.*)/; $tf_sub->($1) }, $_] } 12156 keys %orte); 12157 } 12158 } 12159 12160 eval { 12161 if ($lb->can("Cache")) { 12162 $lb->Cache(1); 12163 } 12164 }; 12165 12166 my $show_sub = sub { 12167 my %args = @_; 12168 my $lb_index = ($splitter 12169 ? $lb->info('anchor') 12170 : $lb->index('active') 12171 ); 12172 return if !defined $lb_index; 12173 my $index; 12174 if ($sorted eq 'unsorted') { 12175 $index = $lb_index; 12176 } else { 12177 my $ort = ($splitter 12178 ? $lb->info("data", $lb_index) 12179 : $lb->get($lb_index) 12180 ); 12181 $index = $orte{$ort}; 12182 } 12183 my $tcoords = []; 12184 $args{'-type'} = $type; 12185 if ($type eq 'o' || $type eq 'p') { # XXX is 'p' OK here? 12186 my $p = $object->get($index)->[Strassen::COORDS]->[0]; 12187 $p = $conv->($p) if $conv; 12188 $tcoords->[0][0] = [ transpose(split /,/, $p) ]; 12189 } else { 12190 my @i = split(/,/, $index); 12191 my $i; 12192 foreach $i (@i) { 12193 my $r = $object->get($i); 12194 my @c = @{ $r->[Strassen::COORDS] }; 12195 if ($conv) { 12196 @c = map { $conv->($_) } @c; 12197 } 12198 push @{$tcoords}, [ transpose_all(@{ Strassen::to_koord(\@c) }) ]; 12199 } 12200 if ($linetype =~ /^p/) { 12201 $args{'-width'} = 20; 12202 $args{'-type'} = "$type-bg"; 12203 } else { 12204 # Is it an area or rectangle? 12205 if (@{$tcoords->[0]} >= 2 && 12206 "$tcoords->[0][0][0],$tcoords->[0][0][1]" eq 12207 "$tcoords->[0][-1][0],$tcoords->[0][-1][1]") { 12208 # Use first point (usually upper left?) 12209 $args{'-scrollto'} = $tcoords->[0][0]; 12210 } else { 12211 # Use middle point of first segment: 12212 $args{'-scrollto'} = $tcoords->[0][$#{$tcoords->[0]}/2]; 12213 } 12214 } 12215 } 12216 $action->(-coords => $tcoords, 12217 '-index' => $index, 12218 -showbutton => $showb, 12219 -cancelbutton => $closeb, 12220 -clever_center => 1, 12221 %args, 12222 ); 12223 }; 12224 12225 if ($args{'-markstart'}) { 12226 my $markstart_sub = sub { 12227 my($type) = @_; 12228 my $lb_index = $lb->index('active'); 12229 return if !defined $lb_index; 12230 my $index = $orte{$lb->get($lb_index)}; 12231 my @i = split(/,/, $index); 12232 my $r = $object->get($i[0]); 12233 my $coords = $r->[Strassen::COORDS]; 12234 my $coord = $coords->[$#$coords/2]; # choose middle one 12235 if ($type eq 'start') { 12236 set_route_start($coord); 12237 } else { 12238 set_route_ziel($coord, -caller => "chooseort"); 12239 } 12240 if ($type eq 'start' || $zoom_new_route_chooseort == 0) { 12241 $show_sub->(); 12242 } 12243 }; 12244 $markf->Label(-text => M('Markieren als').' ...', 12245 -font => $font{'small'}, 12246 )->pack(-side => 'left'); 12247 $markf->Button(-text => M"Start", 12248 -command => sub { $markstart_sub->('start') }, 12249 )->pack(-side => 'left'); 12250 $markf->Button(-text => M"Ziel", 12251 -command => sub { $markstart_sub->('ziel') }, 12252 )->pack(-side => 'left'); 12253 } 12254 12255 my @bfb; 12256 $showb = $f->Button(Name => 'show', 12257 -command => sub { $show_sub->() }, 12258 ); 12259 push @bfb, $showb; 12260 $showb->bind("<2>" => sub { $show_sub->(-zoom_view => 1) }); 12261 $showb->bind("<3>" => sub { $show_sub->(-dont_center => 1) }); 12262 $closeb = $f->Button(Name => 'close', 12263 -command => sub { 12264 if ($ondestroy) { 12265 $ondestroy->($t); 12266 } else { 12267 if ($t->can("withdraw")) { 12268 $t->withdraw; 12269 } else { 12270 $t->destroy; 12271 } 12272 } 12273 }, 12274 ); 12275 push @bfb, $closeb; 12276 pack_buttonframe($f, \@bfb); 12277 12278 $t->bind('<<CloseWin>>' => sub { $closeb->invoke }); 12279 for (qw(Return Double-1 2)) { 12280 $lb->bind("<$_>", sub { $showb->invoke }); 12281 } 12282 my $find_and_select_nearest = sub { 12283 my($w, $y) = @_; 12284 my $inx = $w->nearest($y); 12285 $w->selectionClear(0, "end"); 12286 $w->selectionSet($inx); 12287 $w->activate($inx); 12288 }; 12289 $lb->bind("<2>" => 12290 [sub { 12291 $find_and_select_nearest->(@_); 12292 $show_sub->(-zoom_view => 1); 12293 }, Ev('y')]); 12294 $lb->bind("<3>" => 12295 [sub { 12296 $find_and_select_nearest->(@_); 12297 $show_sub->(-dont_center => 1); 12298 }, Ev('y')]); 12299 $lb->focus; 12300 }; 12301 warn __LINE__ . ": $@" if $@; 12302 DecBusy($top); 12303 12304 $choose_ort_cache{"$linetype-$type"} = 12305 get_cache_identifier($linetype, $type); 12306 if ($t->isa("Tk::Wm") && $do_popup) { 12307 if (@popup_style == 0) { 12308 if (eval {require Tk::Placement; 1; }) { 12309 # XXX use placer also for other toplevels --- replace 12310 # all Popup(@popup_style) calls? 12311 Tk::Placement::placer($t, -screen => $c, 12312 -addx => 20, -addy => 25, # XXX for fvwm 12313 ); 12314 } else { 12315 $t->Popup(-overanchor => "nw", -popanchor => "nw", -popover => $c); 12316 } 12317 } else { 12318 my_popup($t); 12319 } 12320 } 12321 } else { 12322 my $t = $toplevel{"chooseort-$type-$linetype"}; 12323 $t->deiconify; 12324 # win32 ben�tigt zus�tzliches raise 12325 $t->raise; 12326 $lb = $t->Subwidget("Listbox"); 12327 } 12328 12329 if (defined $see) { 12330 if ($splitter) { 12331 TRY: { 12332 for my $inx ($lb->info('children')) { 12333 if ($lb->itemCget($inx, 0, '-text') eq $see) { 12334 $lb->see($inx); 12335 $lb->anchorSet($inx); 12336 last TRY; 12337 } 12338 } 12339 # XXX inconsistency: in splitter/HList mode, do only 12340 # exact match, no substring match 12341 warn "Cannot find <$see> in listbox content"; 12342 } 12343 } else { 12344 my $found_index; 12345 TRY: { 12346 # first: exact match 12347 for my $inx (0 .. $lb->index("end")-1) { 12348 if ($lb->get($inx) eq $see) { 12349 $found_index = $inx; 12350 last TRY; 12351 } 12352 } 12353 # then: substring match 12354 for my $inx (0 .. $lb->index("end")-1) { 12355 if (index($lb->get($inx), $see) >= 0) { 12356 $found_index = $inx; 12357 last TRY; 12358 } 12359 } 12360 warn "Cannot find <$see> in listbox content"; 12361 } 12362 if (defined $found_index) { 12363 $lb->see($found_index); 12364 $lb->selectionSet($found_index); 12365 } 12366 } 12367 } 12368 12369} 12370 12371# Spezialisierung von choose_ort f�r Stadtstra�en 12372### AutoLoad Sub 12373sub choose_streets { 12374 choose_ort(qw(s s), 12375 -markstartifactive => 1, 12376 (!$city_obj->is_osm_source 12377 ? (-completelistbutton => sub { choose_from_plz(-interactive => 1) }, 12378 -completelistbuttonlabel => "Alle Stra�en" 12379 ) 12380 : () 12381 ) 12382 ); 12383} 12384 12385# Markiert einen Punkt und/oder zentriert darauf Als Argumente werden 12386# Canvas-Koordinaten erwartet (Ergebnis von transpose), entweder als 12387# -x/-y, als -point oder als -coords-Argument (komplizierter, siehe 12388# Source) 12389# Weitere Optionen: 12390# -dont_mark: nur zentrieren, aber nicht markieren 12391# -dont_center: nur markieren, aber nicht zentrieren 12392# -clever_center: m�glichst so zentrieren, dass die Markierung nicht durch 12393# andere Fenster verdeckt wird 12394# -dont_delete_old: alte Markierungen beibehalten 12395# -endlessmark: ? 12396# -addtag => $tag : add another tag to the canvas item; this is used as the point name 12397# -addtag => \@tags : add more than one tag; by convention the first additional tag is used as the point name 12398# -inactive: Markierung reagiert nicht auf Events (insbesondere Tooltips) 12399### AutoLoad Sub 12400sub mark_point { 12401 my(%args) = @_; 12402 my($tx, $ty); 12403 if (exists $args{'-x'} && exists $args{'-y'}) { 12404 ($tx, $ty) = ($args{'-x'}, $args{'-y'}); 12405 } elsif (exists $args{'-point'}) { 12406 ($tx, $ty) = split /,/, $args{'-point'}; 12407 } else { 12408 ($tx, $ty) = ($args{'-coords'}->[0][0][0], $args{'-coords'}->[0][0][1]); 12409 } 12410 my $width = $args{'-width'} || 9; 12411 my $do_also_overview_canvas = Tk::Exists($overview_canvas); 12412 if (!$args{'-dont_mark'} && !$args{'-dont_delete_old'}) { 12413 $c->delete('show'); 12414 if ($do_also_overview_canvas) { 12415 $overview_canvas->delete('show'); 12416 } 12417 } 12418 my @show_mark_args; 12419 if ($args{-endlessmark}) { 12420 push @show_mark_args, -endlessmark => 1; 12421 } 12422 unless ($args{'-dont_mark'}) { 12423 my(@tags) = ('show'); 12424 if (exists $args{'-addtag'}) { 12425 if (ref $args{'-addtag'} eq 'ARRAY') { 12426 push @tags, @{$args{'-addtag'}}; 12427 } else { 12428 push @tags, $args{'-addtag'}; 12429 } 12430 } 12431 my @common_args = (-capstyle => $capstyle_round, 12432 ($args{-inactive} ? (-state => "disabled") : ()), 12433 -tags => \@tags, 12434 ); 12435 $c->createLine($tx, $ty, $tx, $ty, 12436 -width => $width, 12437 -fill => $mark_color, 12438 @common_args, 12439 ); 12440 if ($do_also_overview_canvas) { 12441 my($otx,$oty) = _convert_transposed_to_overview_coord($tx, $ty); 12442 $overview_canvas->createLine($otx,$oty,$otx,$oty, 12443 -width => 2, 12444 -fill => $mark_color_overview, 12445 @common_args, 12446 ); 12447 } 12448 show_mark(undef, @show_mark_args); 12449 } 12450 if (!$args{'-dont_center'}) { 12451 if ($args{'-clever_center'} && clever_center($tx, $ty)) { 12452 # NOP 12453 } else { 12454 $c->center_view($tx, $ty); 12455 } 12456 } 12457 unless ($args{'-dont_mark'}) { 12458 eval { local $SIG{__DIE__}; $c->lower('show', $args{'-type'}) }; 12459 } 12460} 12461 12462sub clever_center { 12463 my($tx,$ty,$tx2,$ty2) = @_; 12464 # For now, $tx2 and $ty2 are not used, but should be used to move 12465 # the region towards this point. See Tk::CanvasUtil::center_view2. 12466 return 0 if (!eval { require Tk::Placement; 1 }); 12467 # Is ($tx/$ty) already visible? Then do nothing 12468 my($rx, $ry) = ($c->rootx+$c->widgetx($tx), $c->rooty+$c->widgety($ty)); 12469 my $curr_w = $top->containing($rx, $ry); 12470 { local $^W = 0; return 1 if $curr_w eq $c; } 12471 my @win = Tk::Placement::get_toplevel_regions($top); 12472 if (!@win) { # no clever placement needed --- fallback to normal center 12473 return 0; 12474 } 12475 for (@win) { 12476 # adjust to canvas frame 12477 $_->{"x"} -= $c->rootx; 12478 $_->{"y"} -= $c->rooty; 12479 } 12480 my $box_w = $top->width/3; 12481 my $box_h = $top->height/3; 12482 my $dim = {width=>$box_w,height=>$box_h}; 12483 my $scr = {x=>0,y=>0,width=>$c->width,height=>$c->height}; 12484 my($px,$py) = Tk::Placement::Clever::placement 12485 ($dim, $scr, \@win, 0, 0, 0); 12486 $px += $box_w/2; # move to center of box 12487 $py += $box_h/2; 12488 $c->scroll_canvasxy_to_rootxy($tx,$ty, 12489 $c->rootx+$px,$c->rooty+$py); 12490 1; 12491} 12492 12493# Markiert und/oder zentriert auf die Linie 12494# Coordinates must be map coords, not BBBike standard coords 12495# (that is, use transpose()) 12496# Important arguments: 12497# -coords => [[[x,y],[x2,y2]], # first line 12498# [[x3,y3],[x4,y4]], # second line 12499# ] 12500# -labels => ["first line", "second line" ...] 12501# -scrollto => [x,y] 12502# -dont_mark => 1: don't mark 12503# -dont_center => 1: don't center 12504### AutoLoad Sub 12505sub mark_street { 12506 my(%args) = @_; 12507 my $do_also_overview_canvas = Tk::Exists($overview_canvas); 12508 unless ($args{'-dont_delete_old'}) { 12509 $c->delete('show'); 12510 if ($do_also_overview_canvas) { 12511 $overview_canvas->delete('show'); 12512 } 12513 } 12514 my @res_coords; 12515 # adapt width of mark 12516 my $line_width = $args{'-linewidth'} || get_line_width("s-H")+6; # outline takes 2 pixels... 12517 my $point_width = $args{'-pointwidth'} || $line_width+6; 12518 my @labels = $args{'-labels'} ? @{ $args{'-labels'} } : (); 12519 my($minx, $miny, $maxx, $maxy); 12520 my @all_coords = (); 12521 foreach (@{$args{'-coords'}}) { 12522 my @coords = @$_; 12523 @res_coords = (); 12524 foreach (@coords) { 12525 if (ref $_ eq 'ARRAY') { 12526 if (!defined $minx || $_->[0] < $minx) { $minx = $_->[0] } 12527 if (!defined $maxx || $_->[0] > $maxx) { $maxx = $_->[0] } 12528 if (!defined $miny || $_->[1] < $miny) { $miny = $_->[1] } 12529 if (!defined $maxy || $_->[1] > $maxy) { $maxy = $_->[1] } 12530 } 12531 push @res_coords, (ref $_ eq 'ARRAY' 12532 ? ($_->[0], $_->[1]) 12533 : $_); 12534 } 12535 push @all_coords, @res_coords; 12536 unless ($args{'-dont_mark'}) { 12537 my $label = shift @labels; 12538 my @common_args = (-tags => ['show', (defined $label ? $label : ())], 12539 ($args{-inactive} ? (-state => "disabled") : ()), 12540 ); 12541 if ($args{'-polygon'}) { 12542 if (@res_coords == 2) { 12543 push @res_coords, (@res_coords) x 2; 12544 } 12545 $c->createPolygon(@res_coords, 12546 -width => 5, 12547 -fill => $mark_color, 12548 @common_args, 12549 ); 12550 if ($do_also_overview_canvas) { 12551 my @overview_coords; 12552 for(my $i=0; $i<$#res_coords; $i+=2) { 12553 push @overview_coords, _convert_transposed_to_overview_coord(@res_coords[$i,$i+1]); 12554 } 12555 $c->createPolygon(@overview_coords, 12556 -width => 1, 12557 -fill => $mark_color_overview, 12558 @common_args, 12559 ); 12560 } 12561 } elsif (@res_coords) { 12562 my @add_args; 12563 if (@res_coords == 2) { 12564 push @res_coords, @res_coords; 12565 push @add_args, -capstyle => $capstyle_round, 12566 -width => $point_width; 12567 } else { 12568 push @add_args, -width => $line_width, 12569 } 12570 $c->createLine(@res_coords, 12571 @add_args, 12572 @common_args, 12573 ); 12574 if ($do_also_overview_canvas) { 12575 my @overview_coords; 12576 for(my $i=0; $i<$#res_coords; $i+=2) { 12577 push @overview_coords, _convert_transposed_to_overview_coord(@res_coords[$i,$i+1]); 12578 } 12579 if (@overview_coords == 2) { 12580 push @overview_coords, @overview_coords; 12581 push @add_args, -capstyle => $capstyle_round; 12582 } 12583 my %add_args = @add_args; 12584 $add_args{-width} = 1; # overwrite 12585 $overview_canvas->createLine(@overview_coords, 12586 %add_args, 12587 @common_args, 12588 ); 12589 } 12590 } 12591 } 12592 } 12593 show_mark() unless $args{'-dont_mark'}; 12594 if ($args{'-zoom_view'} && defined $minx) { 12595 zoom_view($minx, $miny, $maxx, $maxy); 12596 } else { 12597 my($vx,$vy); 12598 if ($args{'-scrollto'}) { 12599 ($vx,$vy) = @{ $args{'-scrollto'} }; 12600 } elsif (!$args{'-dont_scroll'}) { 12601 # Prefer an already visible point to scroll to 12602 ($vx,$vy) = find_visible_point(\@all_coords); 12603 if (!defined $vx) { 12604 ($vx,$vy) = @all_coords[0,1]; 12605 } 12606 } 12607 if (!$args{'-dont_center'}) { 12608 if ($args{'-clever_center'} && clever_center($vx,$vy,@all_coords[$#all_coords-1,$#all_coords])) { 12609 # NOP 12610 } else { 12611 $c->center_view2($vx,$vy,@all_coords[$#all_coords-1,$#all_coords]); 12612 } 12613 } 12614 } 12615 unless ($args{'-dont_mark'}) { 12616 eval { local $SIG{__DIE__}; $c->lower('show', $args{'-type'}) }; 12617 } 12618} 12619 12620sub delete_markers { 12621 $c->delete('show'); 12622 if (Tk::Exists($overview_canvas)) { 12623 $overview_canvas->delete('show'); 12624 } 12625 if ($showmark_after) { 12626 $showmark_after->cancel; 12627 undef $showmark_after; 12628 } 12629} 12630 12631sub find_visible_point { 12632 my($c_ref) = @_; 12633 my($x1,$y1,$x2,$y2) = $c->get_corners; 12634 for(my $i = 0; $i < $#$c_ref; $i+=2) { 12635 my($cx,$cy) = @{$c_ref}[$i,$i+1]; 12636 if (point_in_grid($cx,$cy,$x1,$y1,$x2,$y2)) { 12637 return($cx,$cy); 12638 } 12639 } 12640 (); 12641} 12642 12643# Dialog zum Auswahl eines Stra�e aus der Postleitzahl-Datenbank 12644### AutoLoad Sub 12645sub choose_from_plz { 12646 my(%args) = @_; 12647 12648 return if !defined $city || $city ne "Berlin"; 12649 12650 my $batch = (defined $args{'-str'} || defined $args{'-coord'}); 12651 if (!$batch) { 12652 if ($toplevel{"chooseplz"} && Tk::Exists($toplevel{"chooseplz"})) { 12653 $toplevel{"chooseplz"}->deiconify; 12654 $toplevel{"chooseplz"}->raise; 12655 return; 12656 } 12657 } 12658 12659 my $plz = make_plz(); 12660 if (!$plz) { 12661 $plzmcmd->configure(-state => 'disabled'); 12662 status_message(M"Keine PLZ-Datenbank vorhanden!", 'err'); 12663 return; 12664 } 12665 12666 my $show_sub = sub { 12667 my($street_obj, $dont_mark) = @_; 12668 12669 IncBusy($top); 12670 eval { 12671 if (!defined $str_obj{'s'}) { 12672 $str_obj{'s'} = new Strassen $str_file{'s'}; 12673 } 12674 my $s = $str_obj{'s'}; 12675 if (!defined $str_obj{'z'}) { 12676 $str_obj{'z'} = new Strassen $str_file{'z'}; 12677 } 12678 my $z = $str_obj{'z'}; 12679 die "Str ($s)/PLZ ($z)-Objekt?" if !$s || !$z; 12680 my($street, $bezirk, $plz_nr, $xy) = @$street_obj; 12681 12682 if (defined $xy) { 12683 mark_point(-coords => [[[ transpose(split /,/, $xy) ]]], 12684 -clever_center => $args{-interactive}); 12685 } else { 12686 my(@pos) = $s->choose_street($street, $bezirk); 12687 if (!@pos || !defined $pos[0]) { 12688 12689 # PLZ-Gebiet markieren 12690 $z->init; 12691 while(1) { 12692 my $ret = $z->next; 12693 last if !@{$ret->[Strassen::COORDS]}; 12694 if ($ret->[Strassen::NAME] eq $plz_nr) { 12695 mark_street 12696 (-coords => 12697 [[ transpose_all(@{Strassen::to_koord($ret->[Strassen::COORDS])}) ]], 12698 -type => 's', 12699 -dont_mark => $dont_mark, 12700 -polygon => 1, 12701 ); 12702 return; 12703 } 12704 } 12705 12706 my $plz_re = $plz->make_plz_re($plz_nr); 12707 my @streets = $plz->look($plz_re, Noquote => 1); 12708 @pos = $s->union(\@streets, Nouniq => 1); 12709 if (!@pos) { 12710 die Mfmt("Keine Stra�en im PLZ-Gebiet %s.\n", $plz_nr); 12711 } 12712 } 12713 12714 # Stra�en im PLZ-Gebiet markieren 12715 my $i; 12716 for($i = 0; $i <= $#pos; $i++) { 12717 my $o = $pos[$i]; 12718 mark_street 12719 (-coords => 12720 [[ transpose_all(@{Strassen::to_koord($s->get($o)->[Strassen::COORDS])}) ]], 12721 -type => 's', 12722 -dont_delete_old => ($i != 0), 12723 -dont_center => ($i != $#pos), 12724 -dont_mark => $dont_mark, 12725 ); 12726 } 12727 if (@pos > 1 && !$dont_mark) { 12728 status_message(Mfmt("%s liegt im markierten Gebiet", 12729 $street), 'info'); 12730 } 12731 } 12732 }; 12733 if ($@) { 12734 status_message($@, 'err'); 12735 } 12736 DecBusy($top); 12737 }; 12738 12739 12740 my $str; 12741 if (defined $args{'-str'}) { # auf Stra�e zentrieren 12742 return if ($args{'-str'} eq ""); 12743 $str = $args{'-str'}; 12744 my($matchref) = $plz->look_loop($str, Agrep => 3, Max => 20); 12745 my(@match) = @$matchref; 12746 return if !@match; 12747 $show_sub->($match[0], 1) if !$args{-noshow}; 12748 return $match[0]->[PLZ::LOOK_COORD()]; # return coords 12749 } elsif (defined $args{'-coord'}) { # auf Koordinaten zentrieren 12750 return if ($args{'-coord'} eq ""); 12751 eval { 12752 mark_point(-coords => [[[ transpose(split(/,/, $args{'-coord'})) ]]], 12753 -dont_mark => 1); 12754 }; 12755 warn $@ if $@; 12756 } else { # interaktiv 12757 my $t = $top->Toplevel(-title => M"Auswahl aus kompletter Stra�enliste", 12758 -class => "Bbbike Extended Chooser"); 12759 set_as_toolwindow($t); 12760 $toplevel{"chooseplz"} = $t; 12761 12762 my $bf = $t->Frame->pack(-fill => 'x', -side => "bottom"); 12763 my $strf = $t->Frame->pack(-fill => 'x', -side => "top"); 12764 12765 $strf->Label(-text => M('Stra�e').':' 12766 )->pack(-side => "left"); 12767 my $Entry = 'Entry'; 12768 my @extra_args; 12769 my $this_history_file; 12770 eval { 12771 require Tk::HistEntry; 12772 Tk::HistEntry->VERSION(0.37); 12773 @extra_args = (-match => 1, -dup => 0, #-case => 0 12774 ); 12775 $Entry = 'HistEntry'; 12776 $this_history_file = "$bbbike_configdir/bbbike_street_hist"; 12777 }; 12778 my $e = $strf->$Entry(-textvariable => \$str, 12779 @extra_args, 12780 -width => 30)->pack(-side => "left"); 12781 $e->historyMergeFromFile($this_history_file) 12782 if $e->can('historyMergeFromFile'); 12783 12784 $e->focus; 12785 my $srchb = 12786 $strf->Button(Name => 'search', 12787 -padx => 0, 12788 -pady => 0, 12789 )->pack(-side => "left"); 12790 my $showb; 12791 my $lb = $t->Scrolled('Listbox', 12792 -scrollbars => 'osoe', 12793 )->pack(-fill => "x"); 12794 my @match; 12795 my $show_sub_lb = sub { 12796 $show_sub->($match[$lb->index('active')], 0); 12797 }; 12798 12799 for (qw(Double-1 2)) { 12800 $lb->bind("<$_>" => sub { 12801 $show_sub->($match 12802 [$lb->nearest 12803 ($lb->Subwidget('scrolled' 12804 )->XEvent->y)], 0); 12805 }); 12806 } 12807 $t->OnDestroy(sub { delete $toplevel{"chooseplz"} }); 12808 my $close_window = sub { $t->destroy; }; 12809 my $search_window = sub { 12810 if ($e->can('historyAdd') && 12811 $e->can('historySave')) { 12812 $e->historyAdd; 12813 $e->historySave($this_history_file); 12814 } 12815 12816 IncBusy($t); 12817 eval { 12818 my($matchref) = $plz->look_loop($str, Agrep => 3, Max => 20); 12819 @match = @$matchref; 12820 if (!@match) { 12821 $showb->configure(-state => 'disabled'); 12822 die M"Keine Stra�en gefunden.\n"; 12823 } else { 12824 $lb->delete(0, 'end'); 12825 foreach (@match) { 12826 $lb->insert('end', join("/", @{$_}[0..2])); 12827 } 12828 $lb->selection('set', 0); 12829 $showb->configure(-state => 'normal'); 12830 $lb->focus; 12831 } 12832 }; 12833 if ($@) { 12834 status_message($@, 'err'); 12835 } 12836 DecBusy($t); 12837 }; 12838 $e->bind('<Return>' => $search_window); 12839 $srchb->configure(-command => $search_window); 12840 $t->bind('<<CloseWin>>' => $close_window); 12841 my @bfb; 12842 $showb = $bf->Button 12843 (Name => 'show', 12844 -state => 'disabled', 12845 -command => $show_sub_lb); 12846 push @bfb, $showb; 12847 $lb->bind('<Return>' => $show_sub_lb); 12848 push @bfb, $bf->Button(Name => 'close', 12849 -command => $close_window); 12850 pack_buttonframe($bf, \@bfb); 12851 #$t->Popup(@popup_style); 12852 my($x,$y) = ($c->rootx+10, $c->rooty+10); 12853 $t->geometry("+$x+$y"); 12854 12855 } 12856} 12857 12858# Gibt die aktuelle Fontgr��e f�r die �bergebene Ortskategorie zur�ck. 12859### AutoLoad Sub 12860sub get_orte_label_font { 12861 my($category, $is_overview_canvas) = @_; 12862 my $base_index = 0; 12863 if ($is_overview_canvas) { 12864 $base_index = -2; 12865 } else { 12866 if ($scale >= 6) { 12867 $base_index = 2; 12868 } elsif ($scale >= 3) { 12869 $base_index = 1; 12870 } else { 12871 $base_index = 0; 12872 } 12873 } 12874 my $fix_index = sub { 12875 my $index = shift; 12876 if ($index < 0) { $index = 0 } 12877 $index; 12878 }; 12879 my $font; 12880 # This should handle the range MIN_ORT_CAT .. MAX_ORT_CAT: 12881 if ($category == 0) { 12882 my $index = $fix_index->($base_index + $orte_label_size - 2); 12883 $font = $font{$font[$index] . "-italic"}; 12884 } elsif ($category == 1) { 12885 my $index = $fix_index->($base_index + $orte_label_size - 1); 12886 $font = $font{$font[$index]}; 12887 } elsif ($category <= 2) { 12888 my $index = $fix_index->($base_index + $orte_label_size); 12889 $font = $font{$font[$index]}; 12890 } elsif ($category == 3) { 12891 my $index = $fix_index->($base_index + $orte_label_size + 1); 12892 $font = $font{$font[$index]}; 12893 } elsif ($category == 4) { 12894 $font = $font{$font[$base_index + $orte_label_size+2]}; 12895 } elsif ($category == 5) { 12896 $font = $font{$font[$base_index + $orte_label_size+3]}; 12897 } elsif ($category > 5) { 12898 $font = $font{$font[$base_index + $orte_label_size+4]}; 12899 } else { 12900 die "Unknown category $category"; 12901 } 12902 12903 if (!defined $font) { 12904 $font = $font{'veryhuge'}; 12905 } 12906 12907 $font; 12908} 12909 12910# Zeichnet Orte. 12911# XXX Modus zum Zeichnen von Bezirken 12912### AutoLoad Sub 12913sub plotorte { 12914 my(%args) = @_; 12915 12916 my $std; 12917 my $c = $c; 12918 my $transpose; 12919 my $municipality = $args{-municipality}; 12920 my $type = $args{-type} || 'o'; 12921 my $label_tag = uc($type); 12922 my $is_overview_canvas; 12923 if (exists $args{Canvas}) { 12924 $c = $args{Canvas}; 12925 $std = 0; 12926 $transpose = ($show_overview_mode eq 'region' 12927 ? \&transpose_small 12928 : \&transpose_medium); 12929 $is_overview_canvas = 1; 12930 } else { 12931 $std = 1; 12932 $transpose = \&transpose; 12933 } 12934 12935 # evtl. alte Koordinaten l�schen 12936 if (!$args{FastUpdate}) { 12937 $c->delete($type); 12938 $c->delete($label_tag); 12939 } 12940 12941 delete $pending{"replot-p-$type"}; 12942 12943 if ($std && !$p_draw{$type}) { 12944 undef $p_obj{$type}; 12945 if ($main::lazy_p{$type}) { 12946 bbbikelazy_remove_data("p", $type); 12947 } 12948 return; 12949 } 12950 12951 my $orte = _get_orte_obj($type); 12952 12953 my $lazy = defined $args{-lazy} ? $args{-lazy} : $lazy_plot; 12954 if ($std && $lazy) { 12955 status_message(Mfmt("Layer <%s> gezeichnet", exists $p_attrib{$type} ? $p_attrib{$type}->[ATTRIB_PLURAL] : $type), "info"); 12956 return bbbikelazy_add_data("p", $type, $orte); 12957 } 12958 12959 my $coordsys = $coord_system_obj->coordsys; 12960 12961 destroy_delayed_restack(); 12962 IncBusy($top); 12963 $progress->Init(-dependents => $c, 12964 -label => 'orte'); 12965 eval { 12966 my $place_category = (exists $args{PlaceCategory} 12967 ? $args{PlaceCategory} : $place_category); 12968 my $name_o = (exists $args{NameDraw} 12969 ? $args{NameDraw} : $p_name_draw{$type}); 12970 my $no_overlap_label = (exists $args{NoOverlapLabel} 12971 ? $args{NoOverlapLabel} : $no_overlap_label{$type}); 12972 my $progress_hack = $name_o && $no_overlap_label; 12973 12974 my $complete_str = $orte; 12975 my $diffed_orte = 0; 12976 if (#XXX del? ($edit_mode || $edit_normal_mode) && 12977 $args{FastUpdate}) { 12978 my($new_orte, $todelref) = $orte->diff_orig(-clonefile => 1); 12979 if (!defined $new_orte) { 12980 warn "Not using diff output" if $verbose; 12981 $c->delete($type); # evtl. alte Koordinaten l�schen 12982 $c->delete($label_tag); 12983 } else { 12984 warn "Using diff output" if $verbose; 12985 # XXX not used due to lack of tag $type-$i 12986 #foreach (@$todelref) { 12987 # $c->delete("$type-$_"); 12988 #} 12989 $orte = $new_orte; 12990 $diffed_orte = 1; 12991 } 12992 } 12993 12994 my @orte_coords_labeling; 12995 12996 my $next_meth; 12997 my $i; 12998 my $i_inc; 12999 if ($no_overlap_label) { 13000 $orte->init; 13001 $next_meth = 'next'; 13002 $i = 0; 13003 $i_inc = +1; 13004 } else { 13005 # in diesem Fall sollten die gr��eren Orte _sp�ter_ d.h. �ber 13006 # den kleineren gezeichnet werden 13007 $orte->set_last; 13008 $next_meth = 'prev'; 13009 $i = $orte->count; # XXX off by one??? 13010 $i_inc = -1; 13011 } 13012 my $anzahl_eindeutig = $orte->count; 13013 my $do_outline_text = $do_outline_text{$type}; 13014 13015 my %conv_args; 13016 if ($args{-map}) { 13017 $conv_args{Map} = $args{-map}; 13018 } 13019 my $conv = $orte->get_conversion(%conv_args); 13020 13021 my $draw_sub = eval $plotorte_draw_sub; 13022 die $@ if $@; 13023 13024 my $prog_i = 0; 13025 while(1) { 13026 my $ret = $orte->$next_meth(); 13027 last if !@{$ret->[Strassen::COORDS]}; 13028 $progress->Update($prog_i/$anzahl_eindeutig*($progress_hack ? 0.5 : 1)) 13029 if $prog_i % 80 == 0; 13030 $prog_i++; 13031 $i += $i_inc; 13032 $draw_sub->($ret); 13033 } 13034 13035 if ($type eq 'o') { 13036 for my $def ([0 => {-width => 3, -fill => '#0000c0'}], 13037 [1 => {-width => 3}], 13038 [2 => {-width => 4}], 13039 [3 => {-width => 5}], 13040 [4 => {-width => 6}], 13041 [5 => {-width => 7}], 13042 [6 => {-width => 7}], 13043 ) { 13044 my($cat, $args) = @$def; 13045 my %args = (-capstyle => $capstyle_round, 13046 -fill => '#000080', 13047 %$args, 13048 ); 13049 $c->itemconfigure("OP$cat", %args); 13050 } 13051 } else { 13052 $c->itemconfigure($type, 13053 -capstyle => $capstyle_round, 13054 -width => 5, 13055 -fill => '#000080', 13056 ); 13057 } 13058 13059 if ($name_o) { 13060 if ($no_overlap_label) { 13061 # nach Kategorie sortieren 13062 @orte_coords_labeling 13063 = sort { $b->[3] <=> $a->[3] } @orte_coords_labeling; 13064 my $i = 0; 13065 foreach my $ort_def (@orte_coords_labeling) { 13066 $progress->Update($i/$anzahl_eindeutig*.5+0.5) 13067 if $i % 80 == 0; 13068 $i++; 13069 my($text, $tx, $ty, $cat, $point_item) = @$ort_def; 13070 my $font = get_orte_label_font($cat, $is_overview_canvas); 13071 my(@tags) = ($label_tag, "$label_tag$cat"); 13072 if (!draw_text_intelligent($c, $tx, $ty, 13073 -text => $text, 13074 -font => $font, 13075 -tags => \@tags, 13076 -abk => $label_tag, 13077 )) { 13078 if ($cat <= $place_category+1 || $no_overlap_label eq 'drop_non_fitting') { 13079 $c->delete($point_item); 13080 } else { 13081 my $anchor = 'w'; 13082 $c->createText 13083 ($tx+$xadd_anchor_type->{'o'}{$anchor}, 13084 $ty+$yadd_anchor_type->{'o'}{$anchor}, 13085 -text => $text, 13086 -font => $font, 13087 -tags => \@tags, 13088 -anchor => $anchor, 13089 -justify => 'left', 13090 ); 13091 } 13092 } 13093 } 13094 } 13095 if (!$no_overlap_label && !$municipality && 13096 !$do_outline_text) { 13097 $c->itemconfigure($label_tag, 13098 -anchor => 'w', -justify => 'left'); 13099 } 13100 if ($municipality) { 13101 $c->itemconfigure($label_tag, -fill => '#7e7e7e'); 13102 } elsif (!$do_outline_text) { 13103 $c->itemconfigure($label_tag, -fill => '#000080'); 13104 } 13105 if ($orientation eq 'landscape' && 13106 !$do_outline_text) { 13107 foreach my $category (MIN_ORT_CAT .. MAX_ORT_CAT) { 13108 $c->itemconfigure 13109 ("$label_tag$category", 13110 -font => get_orte_label_font($category, $is_overview_canvas)); 13111 } 13112 } 13113 } 13114 13115 if (!($edit_mode || $edit_normal_mode) && !$municipality) { 13116 change_place_visibility($c); 13117 } 13118 13119 if (($edit_mode || $edit_normal_mode) and !$diffed_orte) { 13120 warn "Try to copy original data" if $verbose; 13121 my $r = $complete_str->copy_orig; 13122 warn "Returned $r" if $verbose; 13123 } 13124 13125 if ($std) { 13126 restack_delayed(); 13127 } 13128 }; 13129 if ($@) { 13130 status_message($@, 'err'); 13131 } 13132 $progress->Finish; 13133 DecBusy($top); 13134} 13135 13136# Zeichnet Labels, wobei versucht wird, �berlappungen zu vermeiden. 13137# Auf $canvas wird gezeichnet, die Koordinaten sind $tx/$ty 13138### AutoLoad Sub 13139sub draw_text_intelligent { 13140 my($canvas, $tx, $ty, %args) = @_; 13141 my @ct_args; 13142 foreach my $arg (qw(-text -font -tags -fill -font)) { 13143 push @ct_args, $arg => $args{$arg} if exists $args{$arg}; 13144 } 13145 # mit welchen Tags �berlappungen vermeiden 13146 my $abkrx = (ref $args{-abk} eq 'ARRAY' 13147 ? '^(' . join('|', @{$args{-abk}}) . ")\$" 13148 : "^$args{-abk}\$"); 13149 # Anchor => X/Y-Versetzung 13150 my $xadd = (exists $args{-xadd} ? $args{-xadd} : $xadd_anchor_type->{'o'}); 13151 my $yadd = (exists $args{-yadd} ? $args{-yadd} : $yadd_anchor_type->{'o'}); 13152 my $check_tag_index = (exists $args{-checktagindex} 13153 ? $args{-checktagindex} 13154 : 0); 13155 LOOP: 13156 foreach my $anchor (qw(w e nw n sw s)) { 13157 my $item = $canvas->createText 13158 ($tx+$xadd->{$anchor}, $ty+$yadd->{$anchor}, 13159 @ct_args, 13160 -anchor => $anchor, 13161 -justify => 'left', 13162 ); 13163 my(@bbox) = $canvas->bbox($item); 13164 if (@bbox) { 13165 my(@overlap) = $canvas->find('overlapping', @bbox); 13166 foreach my $i (@overlap) { 13167 next if $i == $item; 13168 my(@tags) = $canvas->gettags($i); 13169 next if !@tags; 13170 if ($check_tag_index eq 'all') { 13171 foreach my $tag (@tags) { 13172 if ($tag =~ /$abkrx/) { 13173 $canvas->delete($item); 13174 next LOOP; 13175 } 13176 } 13177 } else { 13178 next if !defined $tags[$check_tag_index]; 13179 if ($tags[$check_tag_index] =~ /$abkrx/) { 13180 $canvas->delete($item); 13181 next LOOP; 13182 } 13183 } 13184 } 13185 } 13186 $ {$args{-returnanchor}} = $anchor 13187 if ref $args{-returnanchor} eq 'SCALAR'; 13188 if ($args{-outline}) { 13189 $c->delete($item); 13190 outline_text($c, $tx+$xadd->{$anchor}, $ty+$yadd->{$anchor}, 13191 @ct_args, -anchor => $anchor, 13192 -outlinewidth => $args{-outlinewidth}); 13193 } 13194 return 1; 13195 } 13196 0; 13197} 13198 13199# Zeichnen von Stellen mit Obstvorkommen 13200### AutoLoad Sub 13201sub plotobst { 13202 my(%args) = @_; 13203 13204 my $canvas = $c; 13205 my $transpose = \&transpose; 13206 13207 # evtl. alte Koordinaten l�schen 13208 $canvas->delete('obst'); 13209 13210 delete $pending{'replot-p-obst'}; 13211 13212 if (!$p_draw{'obst'}) { 13213 return; 13214 } 13215 13216 destroy_delayed_restack(); 13217 IncBusy($top); 13218 $progress->Init(-dependents => $canvas, 13219 -label => $p_file{'obst'}); 13220 eval { 13221 my $i = 0; 13222 my $obst = get_strassen_obj($p_file{'obst'}); 13223 $obst->init; 13224 my $anzahl_eindeutig = $obst->count; 13225 while(1) { 13226 my $ret = $obst->next; 13227 last if !@{$ret->[Strassen::COORDS]}; 13228 $progress->Update($i/$anzahl_eindeutig) if $i % 80 == 0; 13229 $i++; 13230 my $type = lc($ret->[Strassen::NAME]); 13231 next if !exists $obst_file{$type}; # XXX warning 13232 if ($ret->[Strassen::COORDS][0] =~ /(-?\d+),(-?\d+)/) { 13233 my($x, $y) = ($1, $2); 13234 my($tx, $ty) = $transpose->($x, $y); 13235 if (!exists $obst_photo{$type}) { 13236 $obst_photo{$type} = load_photo($top, $obst_file{$type}); 13237 } 13238 next if (!defined $obst_photo{$type}); 13239 my $img = $obst_photo{$type}; 13240 $canvas->createImage($tx, $ty, 13241 -image => $img, 13242 -tags => 'obst'); 13243 } 13244 } 13245 13246 restack_delayed(); 13247 }; 13248 if ($@) { 13249 status_message($@, 'err'); 13250 } 13251 $progress->Finish; 13252 DecBusy($top); 13253} 13254 13255### AutoLoad Sub 13256sub draw_bridge { 13257 my($cl,%args) = @_; 13258 my $width = $args{'-width'}||10; 13259 my $color = '#808080'; 13260 my $thickness = 2; # make configurable XXX 13261#XXX complicated code, make nicer! 13262#XXX an den Enden etwas verk�rzen 13263 for(my $i = 0; $i < $#$cl/2-1; $i++) { 13264 my($x1,$y1,$x2,$y2) = @{$cl}[$i*2..$i*2+3]; 13265 my $alpha = atan2($y2-$y1,$x2-$x1); 13266 my $beta = $alpha - pi()/2; 13267 my $delta = $width/2; 13268 my($dx,$dy) = ($delta*cos($beta), $delta*sin($beta)); 13269 $c->createLine($x1+$dx,$y1+$dy,$x2+$dx,$y2+$dy, 13270 -width => $thickness, 13271 -tags => $args{'-tags'}, 13272 -fill => $color, 13273 ); 13274 $c->createLine($x1-$dx,$y1-$dy,$x2-$dx,$y2-$dy, 13275 -width => $thickness, 13276 -tags => $args{'-tags'}, 13277 -fill => $color, 13278 ); 13279 } 13280 { 13281 my $alpha = atan2($cl->[3]-$cl->[1],$cl->[2]-$cl->[0]); 13282 my $beta = $alpha - pi()/2; 13283 my $knick = $alpha - pi()/4; 13284 my $knick2 = $alpha + pi()/4; 13285 my $delta = $width/2; 13286 my $knick_length = $width/2; 13287 my($dx, $dy) = ($delta*cos($beta), $delta*sin($beta)); 13288 my($kx, $ky) = ($knick_length*cos($knick), $knick_length*sin($knick)); 13289 my($k2x, $k2y) = ($knick_length*cos($knick2), $knick_length*sin($knick2)); 13290 $c->createLine($cl->[0]+$dx-$k2x, $cl->[1]+$dy-$k2y, 13291 $cl->[0]+$dx, $cl->[1]+$dy, 13292 -width => $thickness, 13293 -tags => $args{'-tags'}, 13294 -fill => $color, 13295 ); 13296 $c->createLine( 13297 $cl->[0]-$dx, $cl->[1]-$dy, 13298 $cl->[0]-$dx-$kx, $cl->[1]-$dy-$ky, 13299 -width => $thickness, 13300 -tags => $args{'-tags'}, 13301 -fill => $color, 13302 ); 13303 } 13304 13305 { 13306 my $alpha = atan2($cl->[-1]-$cl->[-3],$cl->[-2]-$cl->[-4]); 13307 my $beta = $alpha - pi()/2; 13308 my $knick = $alpha - pi()/4; 13309 my $knick2 = $alpha + pi()/4; 13310 my $delta = $width/2; 13311 my $knick_length = $width/2; 13312 my($dx, $dy) = ($delta*cos($beta), $delta*sin($beta)); 13313 my($kx, $ky) = ($knick_length*cos($knick), $knick_length*sin($knick)); 13314 my($k2x, $k2y) = ($knick_length*cos($knick2), $knick_length*sin($knick2)); 13315 $c->createLine($cl->[-2]+$dx+$kx, $cl->[-1]+$dy+$ky, 13316 $cl->[-2]+$dx, $cl->[-1]+$dy, 13317 -width => $thickness, 13318 -tags => $args{'-tags'}, 13319 -fill => $color, 13320 ); 13321 $c->createLine( 13322 $cl->[-2]-$dx, $cl->[-1]-$dy, 13323 $cl->[-2]-$dx+$k2x, $cl->[-1]-$dy+$k2y, 13324 -width => $thickness, 13325 -tags => $args{'-tags'}, 13326 -fill => $color, 13327 ); 13328 } 13329 13330} 13331 13332### AutoLoad Sub 13333sub draw_tunnel_entrance { 13334 my($cl,%args) = @_; 13335 my $width = $args{'-width'}||20; 13336 my $color = '#505050'; 13337 my $thickness = 3; 13338 my $mounds = delete $args{'-mounds'} || "Tu"; 13339#XXX complicated code, make nicer! 13340 if ($mounds !~ m{^_}) { 13341 my $alpha = atan2($cl->[3]-$cl->[1],$cl->[2]-$cl->[0]); 13342 my $beta = $alpha - pi()/2; 13343 my $knick = $alpha - pi()/4; 13344 my $knick2 = $alpha + pi()/4; 13345 my $delta = $width/2; 13346 my $knick_length = $width/3; 13347 my($dx, $dy) = ($delta*cos($beta), $delta*sin($beta)); 13348 my($kx, $ky) = ($knick_length*cos($knick), $knick_length*sin($knick)); 13349 my($k2x, $k2y) = ($knick_length*cos($knick2), $knick_length*sin($knick2)); 13350 $c->createLine($cl->[0]+$dx-$k2x, $cl->[1]+$dy-$k2y, 13351 $cl->[0]+$dx, $cl->[1]+$dy, 13352 $cl->[0]-$dx, $cl->[1]-$dy, 13353 $cl->[0]-$dx-$kx, $cl->[1]-$dy-$ky, 13354 -width => $thickness, 13355 -tags => $args{'-tags'}, 13356 -fill => $color, 13357 ); 13358 } 13359 if ($mounds !~ m{_$}) { 13360 my $alpha = atan2($cl->[-1]-$cl->[-3],$cl->[-2]-$cl->[-4]); 13361 my $beta = $alpha - pi()/2; 13362 my $knick = $alpha - pi()/4; 13363 my $knick2 = $alpha + pi()/4; 13364 my $delta = $width/2; 13365 my $knick_length = $width/3; 13366 my($dx, $dy) = ($delta*cos($beta), $delta*sin($beta)); 13367 my($kx, $ky) = ($knick_length*cos($knick), $knick_length*sin($knick)); 13368 my($k2x, $k2y) = ($knick_length*cos($knick2), $knick_length*sin($knick2)); 13369 $c->createLine($cl->[-2]+$dx+$kx, $cl->[-1]+$dy+$ky, 13370 $cl->[-2]+$dx, $cl->[-1]+$dy, 13371 $cl->[-2]-$dx, $cl->[-1]-$dy, 13372 $cl->[-2]-$dx+$k2x, $cl->[-1]-$dy+$k2y, 13373 -width => $thickness, 13374 -tags => $args{'-tags'}, 13375 -fill => $color, 13376 ); 13377 } 13378} 13379 13380# L�scht alle derzeitig gezeichneten Stra�en und Punkte und liefert 13381# eine Subroutine zur�ck, mit der die gel�schten Objekte wieder 13382# gezeichnet werden k�nnen. 13383### AutoLoad Sub 13384sub get_plotted { 13385 my(@plotted_p, @plotted_str); 13386 while(my($k,$v) = each %str_draw) { 13387 push @plotted_str, $k if ($v); 13388 } 13389 while(my($k,$v) = each %p_draw) { 13390 push @plotted_p, $k if ($v); 13391 } 13392 sub { 13393 $progress->InitGroup; 13394 foreach (@plotted_p) { 13395 plot('p',$_); 13396 } 13397 foreach (@plotted_str) { 13398 plot('str',$_); 13399 } 13400 $progress->FinishGroup; 13401 } 13402} 13403 13404# Setzt den Canvas in den Landscape-Modus (Default). 13405sub set_landscape { 13406 local($^W) = 0; # wegen sub-Redefinition 13407 $orientation = 'landscape'; 13408 *transpose = \&transpose_ls; 13409 *anti_transpose = \&anti_transpose_ls; 13410 *transpose_small = \&transpose_ls_small; 13411 *transpose_medium = \&transpose_ls_medium; 13412 *anti_transpose_small = \&anti_transpose_ls_small; 13413 *anti_transpose_medium = \&anti_transpose_ls_medium; 13414 delete_overview(); 13415} 13416 13417# Setzt den Canvas in den Portraint-Modus. 13418### AutoLoad Sub 13419sub set_portrait { 13420 local($^W) = 0; # wegen sub-Redefinition 13421 $orientation = 'portrait'; 13422 *transpose = \&transpose_pt; 13423 *anti_transpose = \&anti_transpose_pt; 13424 *transpose_small = \&transpose_pt_small; 13425 *transpose_medium = \&transpose_pt_medium; 13426 *anti_transpose_small = \&anti_transpose_pt_small; 13427 *anti_transpose_medium = \&anti_transpose_pt_medium; 13428 delete_overview(); 13429} 13430 13431# �ndert das aktuelle Koordinatensystem. 13432# XXX verbessern... 13433### AutoLoad Sub 13434sub set_coord_system { 13435 my($o) = @_; 13436 if (!defined $o) { 13437 $o = $Karte::map{'standard'}; 13438 } 13439 my $old_coord_system = $coord_system_obj ? $coord_system_obj->token : ""; 13440 if ($old_coord_system eq $o->token) { 13441 # No change 13442 return; 13443 } 13444 if ($o->token eq 'standard') { 13445 set_landscape(); # XXX set scrollregion 13446 $coord_system = 'standard'; 13447 $scale_coeff = 1; 13448 set_canvas_scale(DEFAULT_SCALE); 13449 } else { 13450 { 13451 local($^W) = 0; 13452 *transpose = sub { ($_[0]*$scale, $_[1]*$scale) }; 13453 *anti_transpose = sub { ($_[0]/$scale, $_[1]/$scale) }; 13454 *transpose_small = sub { ($_[0]*$small_scale_edit, $_[1]*$small_scale_edit) }; 13455 *anti_transpose_small = sub { ($_[0]/$small_scale_edit, $_[1]/$small_scale_edit) }; 13456 *transpose_medium = sub { ($_[0]*$medium_scale_edit, $_[1]*$medium_scale_edit) }; 13457 *anti_transpose_medium = sub { ($_[0]/$medium_scale_edit, $_[1]/$medium_scale_edit) }; 13458 } 13459 $scale_coeff = $o->scale_coeff; 13460 set_canvas_scale(1); 13461 } 13462 @scrollregion = $o->scrollregion; 13463 if ($o->token eq 'standard') { # XXX hack 13464 foreach (@scrollregion) { 13465 $_ *= DEFAULT_SCALE; 13466 } 13467 } 13468 scalecanvas($c, 1); 13469 $coord_system_obj = $o; 13470 undef %hoehe; 13471} 13472 13473# Setzt die GUI f�r den Edit-Mode 13474sub gui_set_edit_mode { 13475 my($onoff) = @_; 13476 if ($onoff) { 13477 $edit_mode_indicator->configure(-fg => 'black'); # XXX don't hardcode 13478 $edit_mode_type->configure(-text => uc($onoff)); 13479 if ($onoff eq 'std-no-orig') { 13480 undef $edit_mode; 13481 $edit_normal_mode = 1; 13482 } else { 13483 $edit_mode = $onoff; 13484 } 13485 $edit_mode_flag = 1; 13486 } else { 13487 $edit_mode_indicator->configure(-fg => $dim_color); 13488 $edit_mode_type->configure(-text => ''); 13489 undef $edit_mode; 13490 undef $edit_normal_mode; 13491 $edit_mode_flag = 0; 13492 } 13493} 13494 13495sub gui_start_bbbike_server { 13496 require BBBikeServer; 13497 if (!BBBikeServer::running()) { 13498 BBBikeServer::create_server($top); 13499 status_message("Der BBBike-Server kann jetzt mit dem Programm <bbbikeclient> angesprochen werden", "info"); 13500 } else { 13501 status_message("Der BBBike-Server l�uft bereits.", "infodlg"); 13502 } 13503} 13504 13505# Zeigt Namen der aktuellen Haltestelle oder des aktuellen Ortes 13506# (unterhalb des Cursors). 13507sub enterpoint { 13508 my $c = shift; 13509 my(@tags) = $c->gettags('current'); 13510 if ($tags[0] eq 'p') { 13511 $act_value{Haltestelle} = $names[$tags[1]]; 13512 $hs_label->configure(-fg => 'black'); 13513 } elsif ($tags[0] eq 'o' || $tags[0] =~ /^[ubr](?:-|_bg)/) { 13514 my $prefix = ''; 13515 my $name = $tags[2]; 13516 if ($tags[0] =~ /^u(?:-|_bg)/) { 13517 $prefix = 'U '; 13518 } elsif ($tags[0] =~ /^b(?:-|_bg)/) { 13519 $prefix = 'S '; 13520 } elsif ($tags[0] =~ /^r(?:-|_bg)/) { 13521 $prefix = 'Bhf. '; # XXX language? 13522 } 13523 $act_value{Haltestelle} = $prefix . $name; 13524 $hs_label->configure(-fg => 'black'); 13525 } elsif ($tags[0] eq 'pp' || $tags[0] =~ /^(L\d+|kn|ki|rest)/) { 13526 if (defined $tags[2] && $tags[2] ne 'current') { 13527 $act_value{Haltestelle} = $tags[2]; 13528 } else { 13529 $act_value{Haltestelle} = ''; 13530 } 13531 if (exists $hoehe{$tags[1]}) { 13532 $act_value{Haltestelle} .= " ($hoehe{$tags[1]}m)"; 13533 } 13534 $hs_label->configure(-fg => 'black'); 13535 } elsif ($tags[0] =~ /sperre/) { 13536 if ($tags[1] eq 'sperre0') { 13537 $act_value{Haltestelle} = $tags[2] || M"tragen notwendig"; 13538 } elsif ($tags[1] =~ /^sperre1/) { 13539 $act_value{Haltestelle} = M("Einbahnstra�e") . 13540 (defined $tags[2] and $tags[2] ne "" ? " - " . $tags[2] : ""); 13541 } elsif ($tags[1] eq 'sperre2') { 13542 if (defined $tags[2] and $tags[2] ne "") { 13543 $act_value{Haltestelle} = $tags[2]; 13544 } else { 13545 $act_value{Haltestelle} = M("gesperrte Stra�e"); 13546 } 13547 } else { 13548 $act_value{Haltestelle} = $tags[2] || ''; 13549 } 13550 $hs_label->configure(-fg => 'black'); 13551 } elsif ($tags[0] =~ /^lsa-/) { 13552 my $exact_cat = $tags[3]; 13553 if ($exact_cat !~ /^lsa-X/) { 13554 $act_value{Haltestelle} = ($exact_cat =~ /^lsa-F/ 13555 ? M"Fu�g�ngerampel" 13556 : ($exact_cat =~ /^lsa-B/ 13557 ? M"Bahn�bergang" 13558 : ($exact_cat =~ /^lsa-Zbr/ 13559 ? M"Zugbr�cke (" . $tags[2] . ")" 13560 : substr($exact_cat, 4, 1) 13561 ) 13562 ) 13563 ); 13564 $hs_label->configure(-fg => 'black'); 13565 } else { 13566 $act_value{Haltestelle} = ""; 13567 } 13568 } elsif ($tags[0] =~ /^show/) { 13569 if (defined $tags[1] && $tags[1] ne 'current') { 13570 $act_value{Haltestelle} = $tags[1]; 13571 $hs_label->configure(-fg => 'black'); 13572 } 13573 if (defined $tags[2] && $tags[1] ne 'current' && $tags[2] ne 'current') { 13574 $act_value{Strasse} = $tags[2]; 13575 $str_label->configure(-fg => 'black'); 13576 } else { 13577 $str_label->configure(-fg => $dim_color); 13578 } 13579 } elsif ($tags[0] =~ /^pl/) { 13580 $act_value{Haltestelle} = $tags[2]; 13581 $hs_label->configure(-fg => 'black'); 13582 } 13583 13584 my @l; 13585 my $str = show_below_str($c); 13586 if (defined $act_value{Haltestelle} 13587 && $act_value{Haltestelle} ne '') { 13588 push @l, $act_value{Haltestelle}; 13589 } 13590 if (defined $str && $str ne '') { 13591 push @l, $str; 13592 } 13593 if (defined $c_balloon) { 13594 if (@l && $use_c_balloon >= 2) { 13595 if ($leave_after) { $leave_after->cancel; undef $leave_after } 13596 my $str = join(" / ", @l); 13597 if (1) { 13598 my $add_str = balloon_info_from_all_tags($c); 13599 if ($add_str) { 13600 $str .= "\n$add_str"; 13601 } 13602 } 13603 $c_balloon->Popup($str); 13604 } else { 13605 $c_balloon->Deactivate; 13606 } 13607 } 13608 13609} 13610 13611# Wird beim Verlassen eines Punktes aufgerufen. 13612sub leavepoint { 13613 $hs_label->configure(-fg => $dim_color); 13614 $c_balloon->Deactivate(undef, -from => "event") if defined $c_balloon; 13615 leavestr(); 13616} 13617 13618# Zeigt aktuellen Stra�enzugnamen. 13619sub enterstr { 13620 my $c = shift; 13621 13622 my @balloon_info = balloon_info_from_all_tags($c); 13623 if (@balloon_info) { 13624 $act_value{Strasse} = $balloon_info[0]; 13625 $str_label->configure(-fg => 'black'); 13626 if (defined $c_balloon) { 13627 TRY_BALLOON: 13628 { 13629 if ($use_c_balloon >= 2) { 13630 if ($leave_after) { 13631 $leave_after->cancel; 13632 undef $leave_after; 13633 } 13634 my $str = balloon_info_from_all_tags($c); 13635 if (defined $str) { 13636 $c_balloon->Popup($str); 13637 last TRY_BALLOON; 13638 } 13639 } 13640 $c_balloon->Deactivate; 13641 } 13642 } 13643 } 13644} 13645 13646# Wird beim Verlassen einer Strecke aufgerufen. 13647sub leavestr { 13648 $str_label->configure(-fg => $dim_color); 13649 $c_balloon->Deactivate(undef, -from => "event") if defined $c_balloon; 13650} 13651 13652# Zeigt den Strecken- und/oder Punktnamen unterhalb der Route. 13653sub enterroute { 13654 my($c, $item) = @_; 13655 return if !defined $c_balloon; 13656 $item = 'current' unless defined $item; 13657 my(@tags) = $c->gettags($item); 13658 my $routenr; 13659 if (defined $tags[2] && $tags[2] eq 'viaflag') { 13660 my($item2,@tags2) = find_below_rx($c, ['^route-'],[1]); 13661 if (defined $item2) { 13662 ($item, @tags) = ($item2, @tags2); 13663 } 13664 } 13665 if (defined $tags[1] && $tags[1] =~ /^route-(.*)/) { 13666 $routenr = $1; 13667 if ($routenr eq "") { warn "@tags" } # XXXXX 13668 } else { 13669 if (!grep { $_ eq "viaflag" } @tags) { 13670 warn "Unexpected: no route number in <@tags>"; 13671 } 13672 return; 13673 } 13674 my @l; 13675 my $str = show_below_str($c); 13676 if (!defined $str) { 13677 # next try with bigger tolerance 13678 my $old_closeenough = $c->cget(-closeenough); 13679 $c->configure(-closeenough => 5); 13680 $str = show_below_str($c); 13681 # restore old tolerance value 13682 $c->configure(-closeenough => $old_closeenough); 13683 } 13684 push @l, Strassen::strip_bezirk($str) if (defined $str); 13685 if (defined $routenr && $routenr >= 0) { # wenn mehr als nur der Startpunkt angew�hlt ist 13686 push @l, s2hm($route_time[$routenr]) . "h" if ($route_time[$routenr]); 13687 push @l, m2km($route_distance[$routenr]) if ($route_distance[$routenr]); 13688 } 13689 if (@l) { 13690 if ($leave_after) { $leave_after->cancel; undef $leave_after } 13691 my $b_str = join(" / ", @l); 13692 if (defined $str && 1) { 13693 my $bi_str = balloon_info_from_all_tags($c); 13694 $bi_str =~ s{\Q$str\E\n?}{} if $bi_str; 13695 $b_str .= "\n" . $bi_str if $bi_str; 13696 } 13697 $c_balloon->Popup($b_str); 13698 } else { 13699 $c_balloon->Deactivate; 13700 } 13701} 13702 13703# Wird beim Verlassen einer Route aufgerufen. 13704sub leaveroute { 13705 if (!$leave_after) { # XXX not well tested yet! 13706 $leave_after = 13707 $c->after(100, sub { 13708 $str_label->configure(-fg => $dim_color); 13709 $c_balloon->Deactivate(1) if defined $c_balloon; 13710 undef $leave_after; 13711 }); 13712 } 13713} 13714 13715# Gibt den ersten Tag aus @allowed_tags aus, der sich unter dem jetzigen 13716# Tag befindet. 13717sub find_below { 13718 my($c, @allowed_tags) = @_; 13719 my $e = $c->XEvent; 13720 my($xx, $yy) = ($c->canvasx($e->x), $c->canvasy($e->y)); 13721 my(@items) = $c->find(overlapping => $xx-1, $yy-1, $xx+1, $yy+1); 13722 my %allowed_tags; 13723 foreach (@allowed_tags) { $allowed_tags{$_} = 1 } 13724 my %res; 13725 # Now using "reverse", so top-most items are preferred 13726 # XXX Hopefully this change does not break anything. 13727 foreach my $item (reverse @items) { 13728 my(@tags) = $c->gettags($item); 13729 if ($allowed_tags{$tags[0]} && !exists $res{$tags[0]}) { 13730 $res{$tags[0]} = $item; 13731 } 13732 } 13733 foreach (@allowed_tags) { 13734 if (exists $res{$_}) { 13735 return ($res{$_}, $c->gettags($res{$_})); 13736 } 13737 } 13738 undef; 13739} 13740 13741# Similar to find_below, but use a list of regexes and restrict to 13742# a list of tag positions. 13743# 13744# The position is determined by the optional argument -cxy => [$cx,$cy], 13745# or the position of the current canvas event. 13746sub find_below_rx { 13747 my($c, $allowed_tags_rxs, $tag_pos, $forbidden_tags_rxs, %args) = @_; 13748 my $cxy = delete $args{-cxy}; 13749 warn "ERROR: Unhandled args: " . join(" ", %args) if %args; # XXX consider to make this a die() 13750 my($cx,$cy); 13751 if ($cxy) { 13752 ($cx, $cy) = @$cxy; 13753 } else { 13754 my $e = $c->XEvent; 13755 ($cx, $cy) = ($c->canvasx($e->x), $c->canvasy($e->y)); 13756 } 13757 13758 my(@items) = $c->find(overlapping => $cx-1, $cy-1, $cx+1, $cy+1); 13759 # Now using "reverse", so top-most items are preferred 13760 ITEM: 13761 foreach my $item (reverse @items) { 13762 my(@tags) = $c->gettags($item); 13763 my @restricted_tags = $tag_pos ? @tags[@$tag_pos] : @tags; 13764 my $ok = 0; 13765 for my $tag (@restricted_tags) { 13766 for my $rx (@$allowed_tags_rxs) { 13767 if ($tag =~ /$rx/) { 13768 if ($forbidden_tags_rxs) { 13769 for my $frx (@$forbidden_tags_rxs) { 13770 if ($tag =~ /$frx/) { 13771 next ITEM; 13772 } 13773 } 13774 } 13775 $ok = 1; 13776 } 13777 } 13778 } 13779 if ($ok) { 13780 return ($item, @tags); 13781 } 13782 } 13783 undef; 13784} 13785 13786# Doc pending XXX 13787# tag list imcomplete, should be roughly the same like in set_bindings XXX 13788sub show_below_str { 13789 my($c) = @_; 13790 my($item, @tags) = find_below($c, 13791 (qw/s sBAB l u b r fz f w/, (map { "comm-$_" } @comments_types)), 13792 ); 13793 return if !defined $item; 13794 $act_value{Strasse} = $tags[1]; 13795 $str_label->configure(-fg => 'black'); 13796 $act_value{Strasse}; 13797} 13798 13799# Guckt zun�chst nach, ob sich darunter eine Route befindet und leitet 13800# bei Erfolg die Bearbeitung an enterroute() weiter, ansonsten wird 13801# show_below_str() verwendet. 13802sub show_below_route_str { 13803 my $c = shift; 13804 my($item, @tags) = find_below($c, qw/route/); 13805 if (!defined $item) { 13806 show_below_str($c); # R�ckgabe: String 13807 } else { 13808 enterroute($c, $item); 13809 undef; # R�ckgabe: undef 13810 } 13811} 13812 13813use vars qw($show_info_url); 13814sub handle_show_info_url { 13815 my($offset,$maxbytes) = @_; 13816 return undef if $offset > length($show_info_url); 13817 substr($show_info_url, $offset, $maxbytes); 13818} 13819 13820# Zeigt Informationen zum aktuellen Tag. 13821### AutoLoad Sub 13822sub show_info { 13823 my($x, $y) = @_; 13824 my(@tags) = $c->gettags('current'); 13825 return if !@tags || !defined $tags[0]; 13826 my($base_tag, $is_p); 13827 13828 my $in_2nd_pass = 0; 13829 my $recursion_breaker=0;#XXX 13830 while (1) { 13831 if($recursion_breaker++>10){die}#XXX 13832 $base_tag = $tags[0]; 13833 @tags = grep { $_ ne "current" } @tags; 13834 $is_p = ($base_tag =~ /-(?:[fb]g|img)$/); 13835 $base_tag =~ s/-(?:[fb]g|img)$//; 13836 last unless !exists $p_file{$base_tag} and !$str_file{$base_tag}; 13837 my($below_item, @below_tags) = find_below($c, qw/s l u b r f w o v fz/); 13838 if (!defined $below_item) { 13839 # 2nd pass: check for markers etc. 13840 my($below_item, @below_tags) = find_below($c, qw/show/); # XXX still necessary? 'show' is now -state=>'disabled' 13841 if (!defined $below_item) { 13842 # XXX Alert! Hardcoded for special osm layer, see BBBikeOsmUtil XXX 13843 %BBBikeOsmUtil::osm_layer = %BBBikeOsmUtil::osm_layer if 0; # cease -w 13844 if (defined $BBBikeOsmUtil::osm_layer{item} && grep { $_ eq 'osm' } @tags) { 13845 # just accept 13846 last; 13847 } else { 13848 main::status_message("Es wurde kein Kartenelement an dieser Position gefunden.", "err"); 13849 warn "Current tags=@tags\nBase tag=$base_tag\nBelow item/tags=$below_item @below_tags"; 13850 return; 13851 } 13852 } 13853 $in_2nd_pass = 1; 13854 } 13855 @tags = @below_tags; 13856 last if $in_2nd_pass; 13857 } 13858 13859 my $index; 13860 if ($#tags >= 3) { 13861 ($index = $tags[3]) =~ s/^$base_tag-//; 13862 #warn $index; 13863 } 13864 my $strname = $tags[1]; 13865 my $good_link_for_strname = 1; 13866 my $outside_berlin = 0; # XXX works only for landstrassen, but not for wasser, flaechen, s/rbahn, sehenswuerdigkeiten ... outside berlin 13867 if ($tags[0] =~ m{^(?: 13868 (?:[ub]|kn)-fg 13869 ) 13870 }x) { 13871 $strname = $tags[2]; 13872 } elsif ($tags[0] eq 'GU-img') { 13873 $strname = $tags[2]; 13874 } elsif ($tags[0] =~ m{^sperre}) { 13875 $strname = $tags[2]; 13876 $good_link_for_strname = 0; 13877 } elsif ($tags[0] =~ m{^(?:qs|hs|ql|hl)}) { 13878 $good_link_for_strname = 0; 13879 } elsif ($tags[0] =~ m{^l$}) { 13880 $outside_berlin = 1; 13881 } elsif ($tags[0] =~ /^lsa/) { 13882 undef $strname; # no meaningful name 13883 } elsif ($tags[0] =~ m{^o$}) { 13884 $outside_berlin = 1; 13885 $strname = $tags[2]; 13886 } 13887 13888 my(@coords) = $c->coords('current'); 13889 my $current_is_label = $c->type('current') eq 'text'; 13890 if (!@coords || @coords > 2 || $current_is_label) { 13891 my($px,$py) = $c->pointerxy; 13892 $px -= $c->rootx; 13893 $py -= $c->rooty; 13894 @coords = ($c->canvasx($px), $c->canvasy($py)); 13895 } 13896 require Karte::Polar; 13897 require Karte::UTM; 13898 require Karte::ETRS89; 13899 my($sx,$sy) = $Karte::Standard::obj->trim_accuracy(anti_transpose($coords[0], $coords[1])); 13900 my($px,$py); 13901 if ($city_obj->can("standard_to_polar")) { 13902 ($px,$py) = $city_obj->standard_to_polar($sx,$sy); 13903 } else { 13904 ($px,$py) = $Karte::Polar::obj->trim_accuracy($coord_system_obj->map2map($Karte::Polar::obj, $sx, $sy)); 13905 } 13906 my @polarcoord = (Karte::Polar::dms_human_readable("lat", Karte::Polar::ddd2dms($py)), 13907 Karte::Polar::dms_human_readable("long", Karte::Polar::ddd2dms($px))); 13908 my @polarcoord2 = (Karte::Polar::dmm_human_readable("lat", Karte::Polar::ddd2dmm($py)), 13909 Karte::Polar::dmm_human_readable("long", Karte::Polar::ddd2dmm($px))); 13910 my($gkk_zone_potsdam, $gkk_easting_potsdam, $gkk_northing_potsdam) = Karte::UTM::DegreesToGKK($py, $px, "Potsdam"); 13911 my($gkk_zone_wgs84, $gkk_easting_wgs84, $gkk_northing_wgs84) = Karte::UTM::DegreesToGKK($py, $px, "WGS 84"); 13912 my($utm_ze, $utm_zn, $utm_x, $utm_y) = Karte::UTM::DegreesToUTM($py, $px, "WGS 84"); 13913 my($etrs_east, $etrs_north) = Karte::ETRS89::UTMToETRS89($utm_ze, $utm_zn, $utm_x, $utm_y); 13914 13915 my @comments; 13916 if (!$str_obj{"comm"}) { 13917 $str_obj{'comm'} = _get_comments_obj(); 13918 } 13919 if (!$comments_pos_net) { 13920 eval { 13921 $comments_pos_net = $str_obj{"comm"}->make_coord_to_pos 13922 (sub { 13923 my $cat = $_[0]->[Strassen::CAT]; 13924 $cat =~ /^(?:CS|[-+][12])/ ? 2 : 0; 13925 }); 13926 }; warn $@ if $@; 13927 } 13928 if ($comments_pos_net && $str_obj{"comm"}) { 13929 eval { 13930 my($first, $second); 13931 (undef,undef,$first,$second) = nearest_line_points_mouse($c); 13932 $first = join(",",@$first); 13933 $second = join(",",@$second); 13934 if (defined $first && defined $second && 13935 $comments_pos_net->{"${first}_${second}"}) { 13936 foreach my $pos (@{$comments_pos_net->{"${first}_${second}"}}) { 13937 my $r = $str_obj{"comm"}->get($pos); 13938 if ($r->[Strassen::NAME] ne $strname) { 13939 push @comments, $r->[Strassen::NAME]; 13940 } 13941 } 13942 } 13943 }; warn $@ if $@; 13944 } 13945 13946 my($area, $total_len); 13947 if (defined $index && $index =~ /^\d+/) { 13948 my $s = eval { get_any_strassen_obj("str", $base_tag) }; 13949 if (!$s) { 13950 $s = get_any_strassen_obj("p", $base_tag); 13951 } 13952 if ($s) { 13953 require Strassen::Stat; 13954 my $r = $s->get($index); 13955# XXX bei weitem noch nicht perfekt: statt des Indexes sollte der 13956# NAME verwendet werden, um alle gleichnamigen Objekte zusammenzufassen 13957# Au�erdem sind manche Gew�sser gleichzeitig Seen und Fl�sse (Havel), bei 13958# diesen sollten aus der Fl�che eine vern�nftige L�nge berechnet werden 13959# und diese zu der normalen L�nge dazuaddiert werden. 13960 if ($r) { 13961 if ($r->[Strassen::CAT()] =~ /^F:/) { 13962 $area = Strassen::area($r); 13963#XXX Noch nicht --- siehe Kommentare in wasserstrassen-orig und data/Makefile 13964# # Inseln abziehen 13965# $s->set_index($index + 1); 13966# while(1) { 13967# my $r = $s->next; 13968# last if !@{ $r->[Strassen::COORDS] }; 13969# last if $r->[Strassen::CAT] ne 'F:I'; 13970# $area - Strassen::area($r) / 1_000_000; 13971# } 13972 } else { 13973 $total_len = Strassen::total_len($r) / 1_000; 13974 } 13975 } 13976 } 13977 } 13978 13979 my $show_info_sub = sub { 13980 my($name, $good_link_for_strname, $outside_berlin, $important_txt_and_tag, $unimportant_txt_and_tag) = @_; 13981 #my $tl_tag = "info-$base_tag"; # one window per canvas type 13982 my $tl_tag = "info"; # one window for all 13983 my $info_top = redisplay_top($top, $tl_tag, 13984 -title => M"Information", 13985 -class => "BbbikePassive", 13986 ); 13987 if (defined $info_top) { 13988 require Tk::ROText; 13989 $info_text = hypertext_widget($info_top); 13990 $info_top->Button(Name => 'close', 13991 -command => sub { $info_top->destroy }, 13992 )->pack(-fill => "x"); 13993 toplevel_checker($info_top); 13994 } else { 13995 $info_top = $toplevel{$tl_tag}; 13996 soft_flash($info_text); 13997 } 13998 13999 my $link_menu = $info_text->Menu(-title => M"Linkmen�", 14000 -tearoff => 0); 14001 14002 my $copy_link = sub { 14003 my($url) = @_; 14004 $show_info_url = $url if defined $url; 14005 14006 $info_top->SelectionOwn; 14007 $info_top->SelectionHandle; # calling this mysteriously solves the closure problem... 14008 $info_top->SelectionHandle(\&handle_show_info_url); 14009 }; 14010 $link_menu->command 14011 (-label => M"Link kopieren", 14012 -command => sub { $copy_link->() }, 14013 ); 14014 my $show_url = sub { 14015 my($linkcount, $url, $my_link_menu) = @_; 14016 $info_text->tagBind 14017 ("link$linkcount", "<ButtonRelease-1>" => sub { 14018 my $url = ref $url eq 'CODE' ? $url->() : $url; 14019 require WWWBrowser; 14020 main::status_message("URL: $url", "info"); 14021 WWWBrowser::start_browser($url); 14022 } 14023 ); 14024 if (!$my_link_menu) { 14025 $my_link_menu = $link_menu; 14026 } 14027 $info_text->tagBind 14028 ("link$linkcount", "<Button-3>" => sub { 14029 my $e = $_[0]->XEvent; 14030 $show_info_url = ref $url eq 'CODE' ? $url->() : $url; 14031 $my_link_menu->Post($e->X, $e->Y); 14032 Tk->break; 14033 }); 14034 }; 14035 14036 # Longest text for first column: 14037 $info_text->configure(-tabs => [$info_text->fontMeasure($font{normal}, "Sonnenuntergang: ")]); 14038 14039 my($yview) = $info_text->yview; 14040 $info_text->delete("1.0", "end"); 14041 my $linkcount = 1; 14042 14043 if (defined $name && $name !~ m{^\s*$}) { 14044 $info_text->insert("end", M("Name")."\n", "bold"); 14045 14046 my $url; 14047 my $common_url; 14048 if ($name =~ m{(https?://\S+)}) { 14049 $url = $1; 14050 } elsif ($good_link_for_strname) { 14051 my $google_url = "http://www.google.com/search?"; 14052 require CGI; 14053 CGI->import('-oldstyle_urls'); 14054 (my $name = $name) =~ s{(str)\.}{$1a�e}gi; 14055 # XXX duplicated in LuiseBerlin.pm 14056 $name =~ s{\[.*\]}{}g; # remove special [...] parts 14057 $name =~ s{:\s+.*}{}g; # also remove everything after ":" 14058 ($name, my @cityparts) = Strasse::split_street_citypart($name); 14059 my $common_q = ($outside_berlin ? '' : qq{Berliner }) . 14060 qq{"$name"} . (@cityparts ? " ".join(" ",@cityparts) : ""); 14061 $url = $google_url . CGI->new({ 'q' => qq{site:de.wikipedia.org $common_q} })->query_string; 14062 $common_url = $google_url . CGI->new({ 'q' => $common_q })->query_string; 14063 } 14064 14065 if (!$url) { 14066 $info_text->insert("end", "$name\n"); 14067 } else { 14068 $info_text->insert("end", $name, "link$linkcount"); 14069 14070 my $www_link_menu = $info_text->Menu(-title => M"Linkmen�", 14071 -tearoff => 0); 14072 $www_link_menu->command 14073 (-label => M"Link kopieren", 14074 -command => sub { $copy_link->($url) }, 14075 ); 14076 if ($common_url) { 14077 $www_link_menu->command 14078 (-label => M"Allgemeine Google-Suche", 14079 -command => sub { 14080 require WWWBrowser; 14081 main::status_message("URL: $common_url", "info"); 14082 WWWBrowser::start_browser($common_url); 14083 } 14084 ); 14085 } 14086 14087 $show_url->($linkcount, $url, $www_link_menu); 14088 $linkcount++; 14089 $info_text->insert("end", "\n"); 14090 } 14091 $info_text->insert("end", "\n"); 14092 } 14093 14094 my $write_txt_and_tag = sub { 14095 my(@txt_and_tag) = @_; 14096 for (my $i=0; $i<=$#txt_and_tag; $i+=2) { 14097 my($txt, $tag) = @txt_and_tag[$i, $i+1]; 14098 for my $txtline (split /\n/, $txt) { 14099 my $pos = 0; 14100 while ($txtline =~ m{^(.*?)((?:ftp|https?)://\S+)}g) { 14101 my($pre_text, $link_text) = ($1, $2); 14102 $info_text->insert("end", $pre_text, $tag); 14103 $info_text->insert("end", $link_text, "link$linkcount"); 14104 $show_url->($linkcount, $link_text); 14105 $linkcount++; 14106 $pos = pos($txtline); 14107 } 14108 $info_text->insert("end", substr($txtline, $pos), $tag); 14109 $info_text->insert("end", "\n"); 14110 } 14111 } 14112 if (@txt_and_tag) { 14113 $info_text->insert("end", "\n\n"); 14114 } 14115 }; 14116 14117 $write_txt_and_tag->(@$important_txt_and_tag) if @{ $important_txt_and_tag || [] }; 14118 14119 my $comment_label_end_index; 14120 if (@comments) { 14121 $info_text->insert("end", M("Kommentare").": ", "bold"); 14122 $comment_label_end_index = $info_text->index("end - 1c"); 14123 $info_text->insert("end", "\t" . join("\n\t", @comments), "comments_text"); 14124 $info_text->insert("end", "\n\n"); 14125 } 14126 if (defined $area) { 14127 my($area_value, $area_unit); 14128 if ($area > 10_000) { 14129 $area_value = $area / 1_000_000; 14130 $area_unit = 'km�'; 14131 } else { 14132 $area_value = $area; 14133 $area_unit = 'm�'; 14134 } 14135 $info_text->insert("end", M("Fl�che") . ":", "bold", 14136 sprintf("\t%.2f %s", $area_value, $area_unit) . M(" (dieses Teilst�ck)"), undef); # XXX Msg 14137 $info_text->insert("end", "\n\n"); 14138 } 14139 if (defined $total_len) { 14140 $info_text->insert("end", M("L�nge") . ":", "bold", 14141 sprintf("\t%.2f km", $total_len) . M(" (dieses Teilst�ck)"), undef); # XXX Msg 14142 $info_text->insert("end", "\n\n"); 14143 } 14144 14145 $info_text->insert("end", "Links\n", "bold"); 14146 # Mapserver XXX move to function for creating URL 14147 my @mapserver_def = ([$BBBike::BBBIKE_MAPSERVER_ADDRESS_URL, 14148 "Mapserver"]); 14149 if ($devel_host) { 14150 push @mapserver_def, [defined $ENV{BBBIKE_TEST_CGIDIR} ? "$ENV{BBBIKE_TEST_CGIDIR}/mapserver_address.cgi" : "http://localhost/bbbike/cgi/mapserver_address.cgi", "Lokaler Mapserver", "is_local"]; 14151 } 14152 14153 my @mapext = $c->get_corners; 14154 @mapext[0,1] = map { int } anti_transpose(@mapext[0,1]); 14155 @mapext[2,3] = map { int } anti_transpose(@mapext[2,3]); 14156 14157 my @layers; 14158 # XXX move mapping or this function to a config-like module 14159 my @str_draw_mapping = ([w => "gewaesser"], 14160 [f => "flaechen"], 14161 [[qw(g gP gD gBO)] => "grenzen"], 14162 [[qw(u b r)] => "bahn"], 14163 [[qw(qs ql)] => "qualitaet"], 14164 [[qw(hs hl)] => "handicap"], 14165 [rw => "radwege"], 14166 [e => "faehren"], 14167 [fz => "fragezeichen"], 14168 [v => "sehenswuerdigkeit"], 14169 ); 14170 my @p_draw_mapping = ([o => "orte"], 14171 [lsa => "ampeln"], 14172 [obst => "obst"], 14173 [sperre => "blocked"], 14174 ); 14175 for my $type (qw(str p)) { 14176 my $mapping = $type eq 'str' ? \@str_draw_mapping : \@p_draw_mapping; 14177 my $draw = $type eq 'str' ? \%str_draw : \%p_draw; 14178 for my $check (@$mapping) { 14179 my($abk, $ms_layer) = @$check; 14180 my $doit; 14181 if (ref $abk eq 'ARRAY') { 14182 for (@$abk) { 14183 if ($draw->{$_}) { 14184 $doit = 1; 14185 last; 14186 } 14187 } 14188 } elsif ($draw->{$abk}) { 14189 $doit = 1; 14190 } 14191 if ($doit) { 14192 push @layers, $ms_layer; 14193 } 14194 } 14195 } 14196 push @layers, "route"; # the "mark" is also in the "route" layer 14197 14198 # XXX maybe use Karte::trim_accuracy instead of int? 14199 my $real_coords = join(",", map { int } anti_transpose($coords[0], $coords[1])); 14200 my $wgs84_coords = "$px,$py"; 14201 14202 if ($city_obj->cityname eq 'Berlin') { # only mapserver links for Berlin data 14203 my $mapserver_logo_photo = load_photo($top, 'mapserver_logo', -persistent => 1); 14204 my $need_indentation = !$mapserver_logo_photo; 14205 for my $def (@mapserver_def) { 14206 my($mapserver_url, $mapserver_label, $is_local) = @$def; 14207 my $url = "$mapserver_url/coords=" . $real_coords; 14208 $url .= "/mapext=" . join(",",@mapext); 14209 if (@layers) { 14210 $url .= "/" . join("/", map { "layer=$_" } @layers); 14211 } 14212 if ($mapserver_logo_photo) { 14213 $info_text->imageCreate("end", -image => $mapserver_logo_photo, 14214 -align => "bottom", -padx => 2, -pady => 2); 14215 } 14216 $info_text->insert("end", $mapserver_label, ["link$linkcount", ($need_indentation ? "iconindent" : ())]); 14217 $show_url->($linkcount, $url); 14218 $info_text->insert("end", "\n"); 14219 $linkcount++; 14220 14221 if ($advanced && !$is_local) { 14222 if ($mapserver_logo_photo) { 14223 $info_text->imageCreate("end", -image => $mapserver_logo_photo, 14224 -align => "bottom", -padx => 2, -pady => 2); 14225 } 14226 $info_text->insert("end", $mapserver_label . " (kurzer Link)", 14227 ["link$linkcount", ($need_indentation ? "iconindent" : ())]); 14228 $show_url->($linkcount, sub { 14229 if (exists $long_url_to_short_url{$url}) { 14230 return $long_url_to_short_url{$url}; 14231 } 14232 if (!eval { require WWW::Shorten; WWW::Shorten->import(); 1 }) { 14233 status_message("Das Modul WWW::Shorten ist nicht vorhanden.", "die"); 14234 } 14235 my $short_url = makeashorterlink($url); 14236 $long_url_to_short_url{$url} = $short_url; 14237 $short_url; 14238 }); 14239 $info_text->insert("end", "\n"); 14240 $linkcount++; 14241 } 14242 } 14243 } 14244 14245 if ($city_obj->cityname eq 'Berlin') { # only bbbike.de links for Berlin data (XXX but maybe bbbike.org links could be done instead?) 14246 my @bbbike_cgi_def = ([$BBBike::BBBIKE_DIRECT_WWW, "BBBike im WWW"]); 14247 if ($devel_host) { 14248 push @bbbike_cgi_def, [defined $ENV{BBBIKE_TEST_CGIDIR} ? "$ENV{BBBIKE_TEST_CGIDIR}/bbbike.cgi" : "http://localhost/bbbike/cgi/bbbike.cgi", "lokal: BBBike im WWW"]; 14249 } 14250 14251 my $zielname = ""; 14252 { 14253 my $is_first = 1; 14254 for my $def (@bbbike_cgi_def) { 14255 my $bbbike_cgi_url = $def->[0]; 14256 14257 my $need_indentation; 14258 if ($srtbike16_icon) { 14259 $info_text->imageCreate("end", -image => $srtbike16_icon, 14260 -align => "bottom", -padx => 2, -pady => 1); 14261 } else { 14262 $need_indentation = 1; 14263 } 14264 14265 $info_text->insert("end", $def->[1], 14266 ["link$linkcount", ($need_indentation ? "iconindent" : ())]); 14267 $info_text->insert("end", " "); 14268 if ($is_first) { 14269 my $zielname_e = $info_text->Entry(-textvariable => \$zielname, 14270 -width => 10); 14271 $info_text->insert("end", " Zielname:"); 14272 $info_text->windowCreate("end", -window => $zielname_e); 14273 $is_first = 0; 14274 } 14275 14276 my $www_link_menu = $info_text->Menu(-title => M"Linkmen�", 14277 -tearoff => 0); 14278 $www_link_menu->command 14279 (-label => M"Link kopieren als Ziel", 14280 -command => sub { $copy_link->() }, 14281 ); 14282 $www_link_menu->command 14283 (-label => M"Link kopieren als Start", 14284 -command => sub { 14285 my $current_start_link_url = $show_info_url; 14286 $current_start_link_url =~ s{ziel}{start}g; 14287 $copy_link->($current_start_link_url); 14288 }); 14289 $www_link_menu->command 14290 (-label => M"Link kopieren als Start und Ziel", 14291 -command => sub { 14292 my $current_start_link_url = $show_info_url; 14293 $current_start_link_url =~ s{ziel}{start}g; 14294 my $complete_link_url = "$current_start_link_url\n$show_info_url"; 14295 $copy_link->($complete_link_url); 14296 }); 14297 14298 $show_url->($linkcount, sub { 14299 require CGI; 14300 # sigh, ";" still makes problems... 14301 my $zielname = $zielname; 14302 if ($Tk::VERSION >= 804) { 14303 $zielname = Encode::encode("iso-8859-1", $zielname); 14304 } 14305 CGI->import('-oldstyle_urls'); 14306 my $q = CGI->new({zielc_wgs84 => $wgs84_coords, 14307 zielname => $zielname, 14308 }); 14309 my $url = "$bbbike_cgi_url?" . $q->query_string; 14310 $url; 14311 }, 14312 $www_link_menu, 14313 ); 14314 $info_text->insert("end", "\n"); 14315 $linkcount++; 14316 } 14317 } 14318 } 14319 14320 if ($advanced 14321 && !$city_obj->is_osm_source # no fragezeichen form link for osm data 14322 && grep { $_ eq 'fz' } @tags 14323 ) { 14324 my $need_indentation = 1; # XXX unless I have an icon 14325 $info_text->insert("end", "fragezeichenform", 14326 ["link$linkcount", ($need_indentation ? "iconindent" : ())]); 14327 $show_url->($linkcount, sub { 14328 require CGI; 14329 my $fragezeichen_comment = $strname; 14330 if ($Tk::VERSION >= 804) { 14331 $fragezeichen_comment = Encode::encode("iso-8859-1", $fragezeichen_comment); 14332 } 14333 CGI->import('-oldstyle_urls'); 14334 my $qs = CGI->new({strname => $fragezeichen_comment, 14335 strname_html => CGI::escapeHTML($fragezeichen_comment), 14336 supplied_coord => $real_coords, 14337 })->query_string; 14338 # XXX $BBBIKE_UPDATE_WWW shows also to root bbbike directory at server 14339 my $url = "$BBBike::BBBIKE_UPDATE_WWW/html/fragezeichenform.html?$qs"; 14340 $url; 14341 }); 14342 $info_text->insert("end", "\n"); 14343 $linkcount++; 14344 } 14345 14346 my($mapscale_scale) = $mapscale =~ /:\s*(\d+)/; 14347 14348 if (!$google_photo) { 14349 $google_photo = load_photo($top, 'google'); 14350 } 14351 if (!$bbbike_google_photo) { 14352 $bbbike_google_photo = load_photo($top, 'bbbike_google'); 14353 } 14354 if (!$google_streetview_photo) { 14355 $google_streetview_photo = load_photo($top, 'google_streetview'); 14356 } 14357 14358 { 14359 my @bbbike_google_map_defs = (($devel_host 14360 ? ["lokal: Google Maps (BBBike)", "http://localhost/bbbike/cgi/bbbikegooglemap.cgi"] 14361 : () 14362 ), 14363 ["Google Maps (BBBike)", $BBBike::BBBIKE_GOOGLEMAP_URL], 14364 ); 14365 for my $def (@bbbike_google_map_defs) { 14366 my($label, $baseurl) = @$def; 14367 my $need_indentation; 14368 if ($bbbike_google_photo) { 14369 $info_text->imageCreate("end", -image => $bbbike_google_photo, 14370 -align => "bottom", -padx => 2, -pady => 1); 14371 } else { 14372 $need_indentation = 1; 14373 } 14374 $info_text->insert("end", $label, 14375 ["link$linkcount", ($need_indentation ? "iconindent" : ())]); 14376 $show_url->($linkcount, sub { 14377 require CGI; 14378 my $center = "$px,$py"; 14379 my $zoom; 14380 if ($mapscale_scale < 2000) { 14381 $zoom = 18; 14382 } elsif ($mapscale_scale < 4000) { 14383 $zoom = 17; 14384 } elsif ($mapscale_scale < 8000) { 14385 $zoom = 16; 14386 } elsif ($mapscale_scale < 16000) { 14387 $zoom = 15; 14388 } else { 14389 $zoom = 14; 14390 } 14391 my $q2 = CGI->new({ center => $center, 14392 zoom => $zoom, 14393 autosel => 1, 14394 maptype => "hybrid", 14395 coordsystem => "polar", 14396 mapmode => "addroute", 14397 }); 14398 my $url = $baseurl . "?" . $q2->query_string; 14399 $url; 14400 }); 14401 $info_text->insert("end", "\n"); 14402 $linkcount++; 14403 } 14404 } 14405 14406 { 14407 my $need_indentation; 14408 if ($google_photo) { 14409 $info_text->imageCreate("end", -image => $google_photo, 14410 -align => "bottom", -padx => 2, -pady => 1); 14411 } else { 14412 $need_indentation = 1; 14413 } 14414 14415 $info_text->insert("end", "Google Maps (Original)", 14416 ["link$linkcount", ($need_indentation ? "iconindent" : ())]); 14417 $show_url->($linkcount, sub { 14418 require CGI; 14419 my $q2 = CGI->new({ ll => "$py,$px" }); 14420 my $url = "http://www.google.com/maps?" . $q2->query_string; 14421 $url; 14422 }); 14423 $info_text->insert("end", "\n"); 14424 $linkcount++; 14425 14426 if ($google_streetview_photo) { 14427 $info_text->imageCreate("end", -image => $google_streetview_photo, 14428 -align => "bottom", -padx => 2, -pady => 1); 14429 } 14430 14431 $info_text->insert("end", "Google Maps (StreetView)", 14432 ["link$linkcount", ($need_indentation ? "iconindent" : ())]); 14433 $show_url->($linkcount, sub { 14434 require CGI; 14435 my $q2 = CGI->new({ cbll => "$py,$px", 14436 layer => 'c', 14437 cbp => '0,0,,0,0', # whatever is the meaning of these params 14438 }); 14439 my $url = "http://www.google.com/maps?" . $q2->query_string; 14440 $url; 14441 }); 14442 $info_text->insert("end", "\n"); 14443 $linkcount++; 14444 } 14445 14446 { 14447 my $need_indentation = 1; 14448 my $show_leaflet_url = sub { 14449 my($baseurl, $linkcount) = @_; 14450 $show_url->($linkcount, sub { 14451 require CGI; 14452 my $scale = 17 - log(($mapscale_scale)/3000)/log(2); 14453 $scale = 18 if $scale > 18; 14454 my $q2 = CGI->new({ mlat => $py, 14455 mlon => $px, 14456 ($Msg::lang eq 'en' ? (lang => "en") : ()), 14457 zoom => int($scale), 14458 }); 14459 my $url = $baseurl . "?" . $q2->query_string; 14460 $url; 14461 } 14462 ); 14463 }; 14464 14465 if ($devel_host) { 14466 $info_text->insert("end", "BBBike Leaflet (local)", 14467 ["link$linkcount", ($need_indentation ? "iconindent" : ())]); 14468 $show_leaflet_url->("http://localhost/bbbike/html/bbbikeleaflet.html", $linkcount); 14469 $info_text->insert("end", "\n"); 14470 $linkcount++; 14471 } 14472 14473 $info_text->insert("end", "BBBike Leaflet", 14474 ["link$linkcount", ($need_indentation ? "iconindent" : ())]); 14475 $show_leaflet_url->($BBBike::BBBIKE_LEAFLET_URL, $linkcount); 14476 $info_text->insert("end", "\n"); 14477 $linkcount++; 14478 } 14479 14480 { 14481 14482 if (!$wikipedia_photo) { 14483 $wikipedia_photo = load_photo($top, 'wikipedia'); 14484 } 14485 14486 my(@x) = Karte::Polar::ddd2dms($px); 14487 my(@y) = Karte::Polar::ddd2dms($py); 14488 push @x, $x[0] < 0 ? do { $x[0] *= -1; "W" } : "E"; 14489 push @y, $y[0] < 0 ? do { $y[0] *= -1; "S" } : "N"; 14490 #my $url = "http://stable.toolserver.org/geohack/geohack.php?params=" . join("_", @y, @x) . "_type:landmark_region:DE-BE"; 14491 my $url = "http://toolserver.org/~geohack/geohack.php?params=" . join("_", @y, @x) . 14492 ($city_obj->cityname eq 'Berlin' ? "_type:landmark_region:DE-BE" : ''); 14493 14494 my $need_indentation; 14495 if ($wikipedia_photo) { 14496 $info_text->imageCreate("end", -image => $wikipedia_photo, 14497 -align => "bottom", -padx => 2, -pady => 1); 14498 } else { 14499 $need_indentation = 1; 14500 } 14501 14502 $info_text->insert("end", "Wikipedia Mapsources", 14503 ["link$linkcount", ($need_indentation ? "iconindent" : ())]); 14504 $show_url->($linkcount, $url); 14505 $info_text->insert("end", "\n"); 14506 $linkcount++; 14507 } 14508 14509 my($px0,$py0,$px1,$py1); 14510 { 14511 my($x0,$y0,$x1,$y1) = $c->get_corners; 14512 my($sx0,$sy0,$sx1,$sy1) = (anti_transpose($x0,$y0), 14513 anti_transpose($x1,$y1)); 14514 if ($city_obj->can("standard_to_polar")) { 14515 ($px0,$px0) = $city_obj->standard_to_polar($sx0,$sy0); 14516 ($px1,$px1) = $city_obj->standard_to_polar($sx1,$sy1); 14517 } else { 14518 ($px0,$py0) = $Karte::Polar::obj->trim_accuracy($coord_system_obj->map2map($Karte::Polar::obj, $sx0, $sy0)); 14519 ($px1,$py1) = $Karte::Polar::obj->trim_accuracy($coord_system_obj->map2map($Karte::Polar::obj, $sx1, $sy1)); 14520 } 14521 } 14522 14523 for my $key (keys %info_plugins) { 14524 my $plugin = $info_plugins{$key}; 14525 14526 my @args = (coords => $real_coords, 14527 street => $strname, 14528 px => $px, 14529 py => $py, 14530 px0 => $px0, # left 14531 px1 => $px1, # right 14532 py0 => $py0, # top 14533 py1 => $py1, # bottom 14534 mapscale_scale => $mapscale_scale, 14535 tags => \@tags, 14536 ); 14537 if ($plugin->{visibility} && !$plugin->{visibility}->(@args)) { 14538 next; 14539 } 14540 14541 my $need_indentation; 14542 if ($plugin->{icon}) { 14543 eval { 14544 $info_text->imageCreate("end", -image => $plugin->{icon}, 14545 -align => "bottom", -padx => 2, -pady => 1); 14546 }; 14547 warn $@ if $@; 14548 } else { 14549 $need_indentation = 1; 14550 } 14551 14552 $info_text->insert("end", $plugin->{name}, 14553 ["link$linkcount", $need_indentation ? 'iconindent' : ()]); 14554 if ($plugin->{using_current_region}) { 14555 $info_text->insert('end', " \x{2610}" # BALLOT BOX 14556 ); 14557 } 14558 $info_text->insert('end', "\n"); 14559 $info_text->tagBind 14560 ("link$linkcount", "<ButtonRelease-1>" => sub { 14561 $plugin->{callback}->(@args); 14562 }); 14563 if ($plugin->{callback_3_std}) { 14564 $info_text->tagBind 14565 ("link$linkcount", "<Button-3>" => sub { 14566 my $e = $_[0]->XEvent; 14567 $show_info_url = $plugin->{callback_3_std}->(@args); 14568 $link_menu->Post($e->X, $e->Y); 14569 Tk->break; 14570 }); 14571 } elsif ($plugin->{callback_3}) { 14572 $info_text->tagBind 14573 ("link$linkcount", "<Button-3>" => sub { 14574 $plugin->{callback_3}->(@args, widget => $_[0]); 14575 }); 14576 } 14577 $linkcount++; 14578 } 14579 14580 { 14581 $info_text->insert("end", "\n\n" . M("Koordinaten") . "\n", "bold"); 14582 if (@polarcoord) { 14583 $info_text->insert("end", M("Polar (DMS)") . ":\t$polarcoord[0]\n\t$polarcoord[1]\n"); 14584 } 14585 if (@polarcoord2) { 14586 $info_text->insert("end", M("Polar (DMM)") . ":\t$polarcoord2[0]\n\t$polarcoord2[1]\n"); 14587 } 14588 if (defined $px && defined $py) { 14589 $info_text->insert("end", M("Polar (DDD)") . ":\t$py\n\t$px\n"); 14590 $info_text->insert("end", M("Polar (DDD,DDD)") . "\t$px,$py\n"); # alternative 14591 } 14592 if (defined $gkk_zone_potsdam) { 14593 $info_text->insert("end", "GKK (Potsdam):\t[$gkk_zone_potsdam] $gkk_easting_potsdam/$gkk_northing_potsdam\n"); 14594 } 14595 if (defined $gkk_zone_wgs84) { 14596 $info_text->insert("end", "GKK (WGS 84):\t[$gkk_zone_wgs84] $gkk_easting_wgs84/$gkk_northing_wgs84\n"); 14597 } 14598 if (defined $utm_ze) { 14599 $info_text->insert("end", "UTM (WGS 84):\t[$utm_ze/$utm_zn] $utm_x/$utm_y\n"); 14600 } 14601 if (defined $etrs_east) { 14602 $info_text->insert("end", "ETRS 89:\t$etrs_east/$etrs_north\n"); 14603 } 14604 if (defined $px && defined $py) { 14605 $info_text->insert("end", "URI:\t"); 14606 my $uri = "geo:$py,$px"; 14607 $info_text->insert("end", $uri, ["link$linkcount"]); 14608 $info_text->insert("end", "\n"); 14609 $info_text->tagBind 14610 ("link$linkcount", "<ButtonRelease-1>" => sub { 14611 $info_text->SelectionOwn; 14612 $info_text->SelectionHandle; # calling this mysteriously solves the closure problem... 14613 $info_text->SelectionHandle(sub { return $uri }); 14614 main::status_message("Geo URI $uri in selection", "info"); 14615 }); 14616 $linkcount++; 14617 } 14618 $info_text->insert("end", "BBBike:\t$sx,$sy\n"); 14619 if (defined $px && defined $py) { 14620 $info_text->insert("end", "Wikipedia-Markup:\tNS=$py|EW=$px"); 14621 } 14622 $info_text->insert("end", "\n"); 14623 } 14624 14625 # Das war der letzte Link 14626 for (1 .. $linkcount) { 14627 $info_text->tagConfigure("link$_", -underline => 1, 14628 -foreground => "blue3"); 14629 $info_text->tagBind("link$_", "<Enter>" => sub { 14630 $info_text->configure(-cursor => "hand2"); 14631 }); 14632 $info_text->tagBind("link$_", "<Leave>" => sub { 14633 $info_text->configure(-cursor => undef); 14634 }); 14635 } 14636 14637 eval { 14638 require Astro::Sunrise; 14639 Astro::Sunrise->VERSION(0.85); 14640 14641 my $get_sun_rise = sub { 14642 my $alt = shift; 14643 Astro::Sunrise::sun_rise($px,$py, $alt); 14644 }; 14645 my $get_sun_set = sub { 14646 my $alt = shift; 14647 Astro::Sunrise::sun_set($px,$py, $alt); 14648 }; 14649 14650 my $sunrise_real = $get_sun_rise->(); 14651 my $sunrise_civil = $get_sun_rise->(-6); 14652 my $sunrise_nautical = $get_sun_rise->(-12); 14653 my $sunrise_astro = $get_sun_rise->(-15); 14654 14655 my $sunset_real = $get_sun_set->(); 14656 my $sunset_civil = $get_sun_set->(-6); 14657 my $sunset_nautical = $get_sun_set->(-12); 14658 my $sunset_astro = $get_sun_set->(-15); 14659 14660 $info_text->insert("end", "\nSonnenaufgang/-untergang\n", "bold"); 14661 $info_text->insert("end", <<EOF); 14662Sonnenaufgang:\t$sunrise_real 14663D�mmerung ab: 14664 b�rgerliche:\t$sunrise_civil 14665 nautische:\t$sunrise_nautical 14666 astronomische:\t$sunrise_astro 14667 14668Sonnenuntergang:\t$sunset_real 14669D�mmerung bis: 14670 b�rgerliche:\t$sunset_civil 14671 nautische:\t$sunset_nautical 14672 astronomische:\t$sunset_astro 14673 14674EOF 14675 }; 14676 warn $@ if $@; 14677 14678 $write_txt_and_tag->(@$unimportant_txt_and_tag) if @{ $unimportant_txt_and_tag || [] }; 14679 14680 if (defined &show_info_ext) { 14681 eval { 14682 my $txt = show_info_ext($c, @tags); 14683 if (defined $txt) { 14684 $info_text->insert("end", "$txt\n"); 14685 } 14686 }; 14687 warn $@ if $@; 14688 } 14689 14690 if (defined $comment_label_end_index) { 14691 $info_text->update; 14692 my @bbox = $info_text->bbox($comment_label_end_index); 14693 $info_text->tagConfigure 14694 ("comments_text", 14695 -lmargin2 => $bbox[0]-1-$info_text->cget(-bd)-$info_text->cget(-highlightthickness), 14696 ); 14697 } 14698 14699 if (defined $yview) { 14700 $info_text->yviewMoveto($yview); 14701 } 14702 14703 }; 14704 14705 my @important_txt_and_tag; 14706 my @info_txt_and_tag; 14707 my @internal_canvas_tags; 14708 14709 FIND_INFO: { 14710 if (defined $str_file{$base_tag} && $str_file{$base_tag} =~ /\.shp$/) { 14711 (my $dbf_file = $str_file{$base_tag}) =~ s/\.shp$/.dbf/; 14712 require BBBikeAdvanced; 14713 my $index; 14714 for (@tags) { 14715 if (/^$base_tag-(\d+)/) { 14716 $index = $1; 14717 last; 14718 } 14719 } 14720 if (defined $index) { 14721 my $dbf_info = get_dbf_info($dbf_file, $index); 14722 if (defined $dbf_info) { 14723 if (@tags > 3) { 14724 my $text = splice @tags, 2, 1; 14725 unshift @tags, $text, ""; 14726 } 14727 push @important_txt_and_tag, "$dbf_info\n", undef; 14728 push @internal_canvas_tags, join("\n", @tags), undef; 14729 last FIND_INFO; 14730 } 14731 } 14732 } 14733 14734 my(%info, $info_file); 14735 eval { 14736 require DB_File; 14737 require Fcntl; 14738 if (!$is_p) { 14739 if ($str_file{$base_tag} !~ m|^/|) { 14740 $str_file{$base_tag} = "$datadir/$str_file{$base_tag}"; 14741 } 14742 $info_file = $str_file{$base_tag} . "-info"; 14743 } else { 14744 if ($p_file{$base_tag} !~ m|^/|) { 14745 $p_file{$base_tag} = "$datadir/$p_file{$base_tag}"; 14746 } 14747 $info_file = $p_file{$base_tag} . "-info"; 14748 } 14749 }; warn $@ if $@; 14750 14751 if ($info_file && tie %info, 'DB_File', $info_file, &Fcntl::O_RDONLY) { 14752 warn "Use $info_file ...\n"; 14753 TRY: { 14754 foreach my $i (1 .. 4) { 14755 if (defined $tags[$i]) { 14756 if (defined $info{$tags[$i]}) { 14757 push @info_txt_and_tag, $info{$tags[$i]}, undef; 14758 last TRY; 14759 } 14760 if ($tags[$i] =~ /^L\d+-(\d+)/) { 14761 my $id = $1; 14762 foreach my $type (qw(s p)) { 14763 if (defined $info{"$type-$id"}) { 14764 push @info_txt_and_tag, $info{"$type-$id"}, undef; 14765 last TRY; 14766 } 14767 } 14768 if (defined $info{$id}) { 14769 push @info_txt_and_tag, $info{$id}, undef; 14770 last TRY; 14771 } 14772 } 14773 } 14774 } 14775 } 14776 push @internal_canvas_tags, join("\n", @tags), undef; 14777 untie %info; 14778 last FIND_INFO; 14779 } 14780 14781 if ($advanced) { 14782 if (@tags > 3) { 14783 my $text = splice @tags, 2, 1; 14784 unshift @tags, $text, ""; 14785 } 14786 14787 # XXX slightly hackish: link to the OSM node/way/... browser 14788 for (@tags) { 14789 if (my($type,$id) = $_ =~ m{^osm-(node|way|relation)-(\d+)$}) { 14790 push @tags, "http://www.openstreetmap.org/browse/$type/$id"; 14791 last; 14792 } 14793 } 14794 14795 push @internal_canvas_tags, join("\n", @tags), undef; 14796 } 14797 } 14798 14799 if (@internal_canvas_tags) { 14800 unshift @internal_canvas_tags, M("Interne Canvas-Tags").":\n", "bold"; 14801 } 14802 if (@info_txt_and_tag) { 14803 unshift @info_txt_and_tag, M("Info").":\n", "bold"; 14804 } 14805 $show_info_sub->($strname, 14806 $good_link_for_strname, 14807 $outside_berlin, 14808 [ 14809 @important_txt_and_tag, 14810 @info_txt_and_tag, 14811 ], 14812 [ 14813 @internal_canvas_tags, 14814 ], 14815 ); 14816} 14817 14818sub hypertext_widget { 14819 my($t, %args) = @_; 14820 14821 require Tk::ROText; 14822 my $info_text = $t->Scrolled('ROText', 14823 -wrap => 'word', 14824 -scrollbars => 'osoe', 14825 -highlightthickness => 0, 14826 -borderwidth => 0, 14827 -insertwidth => 0, 14828 -width => 40, 14829 -height => 30, 14830 )->pack(-expand => 1, -fill => "both"); 14831 # Hack as described in http://wiki.tcl.tk/6101 14832 my $info_real_text = $info_text->Subwidget("scrolled"); 14833 $info_real_text->bindtags(["myTextTag", $info_real_text->bindtags]); 14834 $info_real_text->bind 14835 ("myTextTag", 14836 "<Button-3>", 14837 [sub { 14838 my($w,$x,$y) = @_; 14839 if (grep { /^link/ } $w->tagNames("\@$x,$y")) { 14840 Tk->break; 14841 } 14842 }, Ev("x"), Ev("y")]); 14843 14844 $info_text->tagConfigure("bold", -font => $font{'bold'}); 14845 $info_text->tagConfigure("fixed", -font => $font{'fixed'}); 14846 $info_text->tagConfigure("iconindent", -lmargin1 => 16 + 2); 14847 14848 $info_text; 14849} 14850 14851### AutoLoad Sub 14852sub show_statistics { 14853 my $update_statistics; 14854 $update_statistics = sub { 14855 # XXX some day $dataset should replace all of %str_obj etc. 14856 $dataset = Strassen::Dataset->new if !$dataset; 14857 my $res = BBBikeStats::calculate 14858 (Route->new_from_realcoords(\@realcoords), $dataset); 14859 BBBikeStats::tk_display_result 14860 ($top,$res,-markcommand => sub { 14861 my($realcoordsref) = @_; 14862 14863 my @coordsref; 14864 for (@$realcoordsref) { 14865 push @coordsref, [ map { [transpose(split/,/,$_)] } @$_]; 14866 } 14867 mark_street(-coords => \@coordsref, 14868 -dont_center => 1); 14869 }, 14870 -updatecommand => $update_statistics, 14871 -reusewindow => 1, 14872 ); 14873 }; 14874 14875 IncBusy($top); 14876 eval { 14877 require BBBikeStats; 14878 require Strassen::Dataset; 14879 $update_statistics->(); 14880 }; 14881 my $err = $@; 14882 DecBusy($top); 14883 if ($err) { 14884 return status_message(Mfmt("Fehler: %s", $err), "err"); 14885 } 14886} 14887 14888### AutoLoad Sub 14889sub next_free_layer { 14890 my $max_i = 1; 14891 while($occupied_layer{"L$max_i"}) { 14892 $max_i++; 14893 } 14894 for my $type (\%str_draw, \%p_draw) { 14895 while(my($abk, $val) = each %$type) { 14896 if ($val && $abk =~ /^L(\d+)/ && $1 >= $max_i) { 14897 $max_i = $1+1; 14898 while($occupied_layer{"L$max_i"}) { 14899 $max_i++; 14900 } 14901 } 14902 } 14903 } 14904 my $abk = "L$max_i"; 14905 reset_free_layer($abk); 14906 $abk; 14907} 14908 14909### AutoLoad Sub 14910sub reset_free_layer { 14911 my $abk = shift; 14912 delete $no_overlap_label{$abk}; 14913 delete $layer_active_color{$abk}; 14914 delete $layer_pre_enter_command{$abk}; 14915 delete $layer_post_enter_command{$abk}; 14916 delete $layer_pre_leave_command{$abk}; 14917 delete $layer_post_leave_command{$abk}; 14918 delete $layer_line_width{$abk}; 14919 delete $layer_line_length{$abk}; 14920 delete $layer_category_line_arrow{$abk}; 14921 delete $layer_line_arrow{$abk}; 14922 delete $layer_stipple{$abk}; 14923 delete $layer_line_dash{$abk}; 14924 delete $layer_line_capstyle{$abk}; 14925 delete $layer_category_size{$abk}; 14926 delete $layer_category_color{$abk}; 14927 delete $layer_category_line_width{$abk}; 14928 delete $layer_category_image{$abk}; 14929 delete $layer_category_stipple{$abk}; 14930 delete $layer_category_line_dash{$abk}; 14931 delete $layer_category_capstyle{$abk}; 14932 delete $layer_category_line_shorten{$abk}; 14933 delete $layer_line_shorten{$abk}; 14934 delete $layer_category_line_shorten_end{$abk}; 14935 delete $layer_line_shorten_end{$abk}; 14936 delete $layer_name{$abk}; 14937 delete $layer_icon{$abk}; 14938 delete $p_name_draw{$abk}; 14939 delete $str_name_draw{$abk}; 14940 delete $no_overlap_label{$abk}; 14941 delete $do_outline_text{$abk}; 14942 remove_from_stack($abk); 14943} 14944 14945### AutoLoad Sub 14946sub set_coord_output_sub { 14947 my $_coord_output = shift; 14948 if (defined $_coord_output) { 14949 $coord_output = $_coord_output; 14950 } 14951 (my $undecorated_coord_output = $coord_output) =~ s{:.*}{}; 14952 # XXX warum geht es mit keys, aber nicht mit each!!?!?!?! 14953 foreach my $k (keys %Karte::map) { 14954 #while(my($k,$v) = each %Karte::map) { 14955 my $v = $Karte::map{$k}; 14956 #warn "$k => $v"; 14957 if ($undecorated_coord_output eq $k) { 14958 my $o = $Karte::map{$k}; 14959 if ($edit_mode) { # XXX find better conditional 14960 my $from_o = $Karte::map{'berlinmap'}; # XXX don't hardcode, each edit_mode has its own map-token 14961 if ($coord_output eq 'polar:dms') { 14962 $coord_output_sub = sub { 14963 my(@c) = map { $_ / $scale } transpose(@_); 14964 @c = map { sprintf "%d�%02d'%05.2f\"", Karte::Polar::ddd2dms($_) } $from_o->can('map2map')->($from_o, $o, @c); 14965 @c; 14966 }; 14967 } else { 14968 $coord_output_sub = sub { 14969 my(@c) = map { $_ / $scale } transpose(@_); 14970 @c = map { int } $from_o->can('map2map')->($from_o, $o, @c); 14971 @c; 14972 }; 14973 } 14974 } else { 14975 if ($coord_output eq 'polar:dms') { 14976 $coord_output_sub = sub { 14977 my(@c) = map { sprintf "%d�%02d'%05.2f\"", Karte::Polar::ddd2dms($_) } $o->can('standard2map')->($o, @_); 14978 @c; 14979 }; 14980 } elsif ($coord_output eq 'standard') { 14981 $coord_output_sub = sub { 14982 # force int 14983 my(@c) = map { int } $o->can('standard2map')->($o, @_); 14984 @c; 14985 }; 14986 } else { 14987 $coord_output_sub = sub { 14988 my(@c) = $o->trim_accuracy($o->can('standard2map')->($o, @_)); 14989 @c; 14990 }; 14991 } 14992 } 14993 return; 14994 } 14995 } 14996 14997 if ($coord_output eq 'canvas') { 14998 $coord_output_sub = sub { 14999 my(@c) = transpose(@_); 15000 map { 15001 my $x = $_; 15002 if ($without_zoom_factor) { 15003 $x = $x / $scale; 15004 } 15005 if ($coord_output_int) { 15006 $x = int $x; 15007 } 15008 $x; 15009 } @c; 15010 }; 15011 } elsif ($coord_output ne '') { 15012 die "Unknown value for coordout: $coord_output"; 15013 } 15014} 15015 15016# F�gt interaktiv die angeklickte Stelle in die Route (�ber die 15017# Funktion addpoint_xy) ein, erneuert die Kilometerangaben. 15018sub addpoint_inter { 15019## DEBUG_BEGIN 15020#benchbegin(); 15021## DEBUG_END 15022 my(@tags) = $c->gettags('current'); 15023 return if !@tags; 15024 my $res; 15025 if ($tags[0] eq 'pp' or $tags[0] =~ /^lsa/) { 15026 $res = addpoint_xy(@{Strassen::to_koord1($tags[1])}, 15027 $c->coords('current')); 15028 } elsif ($tags[0] eq 'o') { 15029 $res = addpoint_xy(anti_transpose($c->coords('current')), 15030 $c->coords('current')); 15031 } 15032 return if !defined $res; 15033 updatekm(); 15034 set_flag('via'); 15035 set_flag('ziel'); 15036 # XXX only for slowcpu? 15037 if (!($edit_mode || $edit_normal_mode)) { 15038 # restack_delayed is very slow for many points, so disabled here... 15039 restack_delayed(); 15040 update_route_strname(); 15041 } 15042## DEBUG_BEGIN 15043#benchend(); 15044## DEBUG_END 15045} 15046 15047sub addpoints_xy { 15048 my($realcoords_ref, %args) = @_; 15049 my $canvascoords_ref = delete $args{-canvascoords}; 15050 my $power_cache = {}; 15051 for(my $i = 0; $i <= $#$realcoords_ref; $i++) { 15052 my($cx,$cy); 15053 if ($canvascoords_ref) { 15054 ($cx,$cy) = @{ $canvascoords_ref->[$i] }; 15055 } 15056 addpoint_xy(@{$realcoords_ref->[$i]}, $cx, $cy, -powercache => $power_cache); 15057 } 15058} 15059 15060# Eingaben: $x und $y als realcoords, $xx und $yy als Canvas-Koords 15061sub addpoint_xy { 15062 my($x, $y, $xx, $yy, %args) = @_; 15063## DEBUG_BEGIN 15064#benchbegin(); 15065## DEBUG_END 15066 15067 my $power_cache = delete $args{-powercache}; 15068 15069 if (!defined $xx) { 15070 if ($coord_system ne 'standard') { 15071 warn "NYI: non-standard map mode and not supplied $xx and $yy to addpoint_xy"; 15072 } else { 15073 ($xx, $yy) = transpose($x, $y); 15074 } 15075 } 15076 15077 my($deltax, $deltay, $etappe); 15078 if (@realcoords != 0) { 15079 ($deltax, $deltay) = ($x - $realcoords[-1]->[0], 15080 $y - $realcoords[-1]->[1]); 15081 $etappe = sqrt(sqr($deltax) + sqr($deltay)); 15082 return undef if $etappe == 0; # keine leeren Etappen 15083 15084 # F�hrstrecken von der Gesamtstrecke ausschlie�en: 15085 CHECK_NO_FERRY: { 15086 if ($net) { 15087 my $xy0 = join(",", @{$realcoords[-1]}); 15088 my $xy1 = "$x,$y"; 15089 my $name = ((exists $net->{Net2Name}{$xy0} && $net->{Net2Name}{$xy0}{$xy1}) || 15090 (exists $net->{Net2Name}{$xy1} && $net->{Net2Name}{$xy1}{$xy0})); 15091 if (defined $name && $name =~ /^F�hre /) { 15092 last CHECK_NO_FERRY; 15093 } 15094 } 15095 $strecke += $etappe; 15096 } 15097 } 15098 my($prex, $prey); 15099 push(@coords, [$xx, $yy]); 15100 $nr++; 15101 push(@realcoords, [$x, $y]); 15102 if ($nr == 0) { 15103 ($prex, $prey) = ($xx, $yy); 15104 } else { 15105 ($prex, $prey) = @{$coords[-2]}; 15106 } 15107 my $hw; 15108 $hw = BBBikeCalc::head_wind($deltax, $deltay) if $wind; 15109 my $curr_line = $c->createLine 15110 ($prex, $prey, $xx, $yy, 15111 -width => ($route_below ? int(get_line_width('HH')*2.5) : 5), 15112 ($route_arrowed ? (-arrow => "last") : ()), 15113 # -dash and -capstyle don't work well together 15114 ($route_dashed ? (-dash => [4,5]) : (-capstyle => $capstyle_round)), 15115 -tags => ['route', "route-$nr"]); 15116 if ($nr == 0) { 15117 set_flag('start'); 15118 } 15119 15120 # XXX auch hier m�ssten F�hrstrecken ausgeschlossen werden... wie? 15121 my $v_rel; 15122 if ($bikepwr && $etappe) { 15123 my $wind; # Berechnung des Gegenwindes 15124 { 15125 local $^W = 0; 15126 if ($hw >= 2) { 15127 $wind = -$wind_v; 15128 } elsif ($hw > 0) { # unsicher beim Crosswind 15129 $wind = -$wind_v*0.7; 15130 } elsif ($hw > -2) { 15131 $wind = $wind_v*0.7; 15132 } else { 15133 $wind = $wind_v; 15134 } 15135 } 15136 15137 # Verh�ltnis zwischen der m�glichen Geschwindigkeit, die ohne 15138 # Gegenwind und Steigung erreicht werden kann, und der tats�chlich 15139 # erreichten 15140 15141 for(my $i = 0; $i <= $#power; $i++) { 15142 15143 # In diesem Abschnitt wird versucht, eine Steigung zu finden. 15144 # Wenn %hoehe nicht eingelesen wurde, passiert nichts. 15145 # Wenn die H�hen von beiden Etappenpunkten definiert ist, kann 15146 # die Steigung trivial errechnet werden. Wenn nur die H�he des 15147 # Etappenzielpunktes bekannt ist, wird nachgeguckt, ob in den 15148 # bisherigen Etappenstartpunkten die H�he bekannt ist, und 15149 # bei Erfolg eine Durchschnittssteigung errechnet. 15150 my($prev_x, $prev_y) = @{$realcoords[-2]}; 15151 my $grade; 15152 my @grade_symbol_pos; 15153 my $prev_hoehe = $hoehe{"$prev_x,$prev_y"}; 15154 my $this_hoehe = $hoehe{"$x,$y"}; 15155 my $grade_length = $etappe; 15156 if ($use_hoehe && defined $this_hoehe) { 15157 if (defined $prev_hoehe) { 15158 $grade = ($this_hoehe-$prev_hoehe)/$grade_length; 15159 @grade_symbol_pos = (int(($xx-$prex)/2+$prex)+1, 15160 int(($yy-$prey)/2+$prey)+1); 15161 } else { 15162 for(my $j = $#{$bikepwr_all_time[$i]}; $j >= 0; $j--) { 15163 if (defined $bikepwr_all_time[$i]->[$j][3]) { 15164 my @grade_line; 15165 for(my $k = $j; 15166 $k <= $#{$bikepwr_all_time[$i]}; $k++) { 15167 $grade_length += 15168 $bikepwr_all_time[$i]->[$k][2]; 15169 push @grade_line, @{$coords[$k]}; 15170 } 15171 push @grade_line, $prex, $prey, $xx, $yy; 15172 @grade_symbol_pos = get_polyline_center(@grade_line); 15173 # XXX ist $etappe (und damit $grade_length) 15174 # immer != 0? 15175 $grade = 15176 ($this_hoehe-$bikepwr_all_time[$i]->[$j][3]) 15177 / $grade_length; 15178 for(my $k = $j; 15179 $k <= $#{$bikepwr_all_time[$i]}; $k++) { 15180 $bikepwr_all_time[$i]->[$k][4] = $grade; 15181 } 15182 last; 15183 } 15184 } 15185 } 15186 } 15187 15188 # XXX m�glicherweise Performance-Killer bei reverse_route()? 15189 # Caching verwenden? 15190 my($current_v, $current_C) = bikepwr_get_v($wind, $i, $grade); 15191 if ($coloring eq 'power' && $i == 0) { 15192 $v_rel = (bikepwr_get_v(0, $i, 0))[0] / $current_v; 15193 } 15194 my $bikepwr_time_etappe = $etappe / $current_v; 15195 $bikepwr_time[$i] += $bikepwr_time_etappe; 15196 my $bikepwr_cal_etappe = ($bikepwr_time_etappe 15197 ? $current_C*($bikepwr_time_etappe/3600) 15198 : 0); 15199 $bikepwr_cal[$i] += $bikepwr_cal_etappe; 15200 15201 if (keys %active_speed_power && 15202 $active_speed_power{Type} eq "power" && 15203 $i == $active_speed_power{Index}) { 15204 if (!$nr) { 15205 $route_time[0] = 0; 15206 } else { 15207 $route_time[$nr-1] = 0 if !defined $route_time[$nr-1]; 15208 $route_time[$nr] 15209 = $route_time[$nr-1] + $bikepwr_time_etappe; 15210 } 15211 if (%ampeln && $ampeln{"$x,$y"}) { 15212 $route_time[$nr] += $lost_time_per_ampel{X}; # XXX F... 15213 } 15214 } 15215 15216 my $grade_direction; 15217 if ($show_grade && $i == 0) { 15218 if (!defined $grade) { 15219 make_comments_net() if !$comments_net; 15220 15221 if ($comments_net) { 15222 for my $cat (@{ $comments_net->{Net}{"$prev_x,$prev_y"}{"$x,$y"} }) { 15223 if ($cat =~ /^(St|Gf)/) { 15224 $grade_direction = $1 eq 'St' ? +1 : -1; 15225 last; 15226 } 15227 } 15228 if ($grade_direction) { 15229 @grade_symbol_pos = get_polyline_center($prex, $prey, $xx, $yy); 15230 my $r = $comments_net->get_street_record("$prev_x,$prev_y", 15231 "$x,$y"); 15232 if ($r && $r->[Strassen::NAME] =~ /(\d+)%/) { 15233 $grade = $1 * $grade_direction; 15234 } 15235 $grade_length = Strassen::Util::strecke 15236 ([$prev_x,$prev_y],[$x,$y]); 15237 } 15238 } 15239 } 15240 if ((defined $grade && 15241 (($grade_length >= $grade_minimum_short_length && abs($grade) >= $grade_minimum) || 15242 ($grade_length < $grade_minimum_short_length && abs($grade) >= $grade_minimum_short))) || 15243 (!defined $grade && defined $grade_direction)) { 15244 $c->createImage 15245 (@grade_symbol_pos, 15246 -image => ((defined $grade_direction && $grade_direction > 0) || (defined $grade && $grade > 0) ? $steigung_photo : $gefaelle_photo), 15247 -anchor => 's', 15248 -tags => ['route', "route-$nr"], 15249 ); 15250 15251 if (defined $grade) { 15252 outline_text($c, 15253 @grade_symbol_pos, 15254 -font => $font{'small'}, 15255 -text => float_prec($grade*100, 1) . '%', 15256 -tags => ['route', "route-$nr"], 15257 -outlinewidth => 1, 15258 -anchor => 'nw'); 15259 } 15260 } 15261 } 15262 15263 # Format einer Etappe von @bikepower_all_time 15264 # 0: Zeit f�r die jeweilige Etappe 15265 # 1: Gegenwindgeschwindigkeit (crosswind mit eingerechnet) 15266 # 2: L�nge der Etappe 15267 # 3: H�he des Etappenstartpunktes 15268 # 4: Steigung der Etappe 15269 # 5: Kalorienverbrauch 15270 my @etappe_def = ($bikepwr_time_etappe, $wind, $etappe, 15271 $prev_hoehe, $grade, $bikepwr_cal_etappe); 15272 push(@{$bikepwr_all_time[$i]}, \@etappe_def); 15273 # XXX bikepwr_all_time in dieser Form 15274 # ist eigentlich ineffizient, da nur 15275 # die Zeit f�r die verschiedenen "Power"s unterschiedlich ist, 15276 # die anderen Daten aber alle gleich. 15277 } 15278 } 15279 15280 if (keys %active_speed_power && 15281 $active_speed_power{Type} eq "speed") { 15282 my $i = $active_speed_power{Index}; 15283 if (!$nr) { 15284 $route_time[$nr] = 0; 15285 } else { 15286 $route_time[$nr-1] = 0 if !defined $route_time[$nr-1]; 15287 $route_time[$nr] 15288 = $route_time[$nr-1] + ($etappe / 1000) / $speed[$i] * 3600; 15289 } 15290 if (%ampeln && $ampeln{"$x,$y"}) { 15291 $route_time[$nr] += $lost_time_per_ampel{X}; # XXX F ... 15292 } 15293 } 15294 15295 my $col; 15296 if ($coloring eq 'power' && defined $v_rel) { 15297 if ($v_rel >= 2) { $col = $wind_colors{-2}->[WIND_COLOR_NAME] } 15298 elsif ($v_rel >= 1.3) { $col = $wind_colors{-1}->[WIND_COLOR_NAME] } 15299 elsif ($v_rel >= 0.77) { $col = $wind_colors{0}->[WIND_COLOR_NAME] } 15300 elsif ($v_rel >= 0.5) { $col = $wind_colors{1}->[WIND_COLOR_NAME] } 15301 else { $col = $wind_colors{2}->[WIND_COLOR_NAME] } 15302 } elsif ($wind && $coloring eq 'wind') { 15303 $col = $wind_colors{$hw}->[WIND_COLOR_NAME]; 15304 } elsif ($coloring =~ /^(wind|power)$/) { 15305 $col = 'red'; 15306 } else { 15307 $col = $coloring; # red oder blue 15308 } 15309 $c->itemconfigure($curr_line, -fill => $col) if defined $col; 15310 15311 if (!$nr) { 15312 $route_distance[0] = 0; 15313 } else { 15314 $route_distance[$nr-1] = 0 if !defined $route_distance[$nr-1]; 15315 $route_distance[$nr] = $route_distance[$nr-1] + $etappe; 15316 } 15317 15318## DEBUG_BEGIN 15319#benchend(); 15320## DEBUG_END 15321 15322 1; 15323} 15324 15325### AutoLoad Sub 15326sub get_route_color { 15327 my($value, $min_value, $max_value, $min_index, $max_index) = @_; 15328# my $r = $wind_color{$min_value} 15329} 15330 15331### AutoLoad Sub 15332sub set_flag { 15333 my($type, $x, $y, $leaveold) = @_; 15334 $c->delete($type . 'flag') unless $leaveold; 15335 if ($do_flag{$type} && $flag_photo{$type}) { 15336 if ($type eq 'start' && !defined $x) { 15337 ($x, $y) = @{$coords[0]}; 15338 } elsif ($type eq 'ziel') { 15339 return if (@coords < 2); 15340 ($x, $y) = @{$coords[-1]}; 15341 } elsif ($type eq 'via') { 15342 require BBBikeVia; # XXX should not be necessary 15343 BBBikeVia::show_via_flags(); 15344 return; 15345 } 15346 # XXX $nr may or may not be meaningful here 15347 $c->createImage($x, $y, 15348 -anchor => 'c', 15349 -image => $flag_photo{$type}, 15350 -tags => ['route', "route-$nr", $type . 'flag']); 15351 } 15352} 15353 15354sub skalarprodukt { 15355 my($a1, $a2, $b1, $b2) = @_; 15356 $a1*$b1 + $a2*$b2; 15357} 15358 15359# Eingabe: Gerade mit zwei Endpunkten (Q und R) und Punkt P 15360# Ausgabe: Fu�punkt des Lotes vom Punkt auf die Gerade 15361sub fusspunkt { 15362 my($q1, $q2, $r1, $r2, $p1, $p2) = @_; 15363 my($a1, $a2) = ($r1-$q1, $r2-$q2); # Richtungsvektor berechnen 15364 my $a_sqr = skalarprodukt($a1, $a2, $a1, $a2); 15365 return undef if $a_sqr == 0; 15366 my $zaehler = skalarprodukt($p1-$q1, $p2-$q2, $a1, $a2); 15367 my $t_f = $zaehler / $a_sqr; 15368 ($q1 + $t_f * $a1, $q2 + $t_f * $a2); 15369} 15370 15371### AutoLoad Sub 15372sub recalc_bikepwr { 15373 my $power_cache = {}; 15374 for(my $i = 0; $i <= $#power; $i++) { 15375 $bikepwr_time[$i] = 0; 15376 $bikepwr_cal[$i] = 0; 15377 foreach (@{$bikepwr_all_time[$i]}) { 15378 my $wind = $_->[1]; 15379 my $grade = $_->[4]; 15380 my($v, $C) = bikepwr_get_v($wind, $i, $grade, $power_cache); 15381 my $bikepwr_time_etappe = ($_->[2] / $v); 15382 $bikepwr_time[$i] += $bikepwr_time_etappe; 15383 my $bikepwr_cal_etappe = ($bikepwr_time_etappe 15384 ? $C*($bikepwr_time_etappe/3600) 15385 : 0); 15386 $bikepwr_cal[$i] += $bikepwr_cal_etappe; 15387 $_->[0] = $bikepwr_time_etappe; 15388 $_->[5] = $bikepwr_cal_etappe; 15389 } 15390 } 15391} 15392 15393### AutoLoad Sub 15394sub set_corresponding_power { 15395 @power = (); 15396 for(my $i = 0; $i<=$#speed; $i++) { 15397 my $bp_speed = new BikePower; 15398 $bp_speed->given('v'); 15399 $bp_speed->velocity($speed[$i]/3.6); 15400 $bp_speed->calc; 15401 push @power, int($bp_speed->power); 15402 } 15403 if (!@power) { 15404 @power = (50, 100); 15405 } 15406} 15407 15408### AutoLoad Sub 15409sub redraw_path { 15410 destroy_delayed_restack(); 15411 IncBusy($top); 15412 eval { 15413 my @oldcoords = @coords; 15414 my @oldrealcoords = @realcoords; 15415 my @oldsearchroutepoints = @search_route_points; # hack 15416 resetroute(); 15417 addpoints_xy(\@oldrealcoords, -canvascoords => \@oldcoords); 15418 @search_route_points = @oldsearchroutepoints; 15419 set_flag('via'); 15420 set_flag('ziel'); 15421 updatekm(); 15422 if (!defined $last_route_below || $last_route_below ne $route_below) { 15423 if ($route_below) { 15424 # Hmmm, need to make sure it's over wasser+flaechen XXX 15425 #XXXspecial_lower("route", "delay-restack"); 15426 set_in_stack('route', 'above', '*landuse*'); 15427 } else { 15428 set_in_stack('route', 'above', '*route*'); 15429 } 15430 $last_route_below = $route_below; 15431 } 15432 restack_delayed(); 15433 }; 15434 DecBusy($top); 15435} 15436 15437# Einfaches Umdrehen der Route (kein echter R�ckweg!) 15438### AutoLoad Sub 15439sub reverse_route { 15440 destroy_delayed_restack(); 15441 IncBusy($top); 15442 eval { 15443 my @newcoords = reverse @coords; 15444 my @newrealcoords = reverse @realcoords; 15445 @search_route_points = reverse @search_route_points; 15446 resetroute(); 15447 addpoints_xy(\@newrealcoords, -canvascoords => \@newcoords); 15448 set_flag('via'); 15449 set_flag('ziel'); 15450 updatekm(); 15451 if ($show_strlist) { 15452 show_route_strname(); 15453 } 15454 clear_undecided_temp_blockings(); 15455 check_path_in_blockings_net(\@realcoords); 15456 restack_delayed(); 15457 }; 15458 warn __LINE__ . ": $@" if $@; 15459 DecBusy($top); 15460} 15461 15462# Echte Berechnung des R�ckwegs 15463### AutoLoad Sub 15464sub way_back { 15465 return if @search_route_points < 2; 15466 @search_route_points = reverse @search_route_points; 15467 for(my $i=$#search_route_points-1; $i >= 0; $i--) { 15468 $search_route_points[$i+1]->[SRP_TYPE] = $search_route_points[$i]->[SRP_TYPE]; 15469 } 15470 $search_route_points[0]->[SRP_TYPE] = POINT_MANUELL; 15471 re_search(-undo => 0); 15472 update_route_strname(); 15473} 15474 15475### AutoLoad Sub 15476sub way_back_gui { 15477 IncBusy($top); 15478 eval { way_back() }; 15479 warn $@ if $@; 15480 DecBusy($top); 15481} 15482 15483sub delete_route { 15484 reset_button_command(); 15485 if (@inslauf_selection || @ext_selection) { 15486 require BBBikeAdvanced; 15487 reset_selection(); 15488 } 15489 update_route_strname(); # XXX => hook 15490 if ($map_mode =~ m{^(MM_VIA_MOVE 15491 |MM_GOAL_MOVE 15492 |MM_VIA_ADD 15493 |MM_VIA_ADD_THEN_MOVE 15494 |MM_VIA_DEL 15495 )$}x) { 15496 set_map_mode(MM_SEARCH); 15497 } 15498 15499 hide_blockings_infobar(); 15500 15501 Hooks::get_hooks("del_route")->execute; 15502} 15503 15504### XXX problems, see above 15505# sub delete_route_gui_toggle { 15506# my $menu_index = shift; 15507# delete_route(); 15508# $top->Subwidget(PopupMenu)->entryconfigure 15509# ($menu_index, 15510# -label => M"Route wiederherstellen (Undo)", 15511# -command => sub { get_undo_route_gui_toggle($menu_index) } 15512# ); 15513# } 15514 15515# sub get_undo_route_gui_toggle { 15516# my $menu_index = shift; 15517# get_undo_route(); 15518# $top->Subwidget(PopupMenu)->entryconfigure 15519# ($menu_index, 15520# -label => M"Route l�schen", 15521# -command => sub { delete_route_gui_toggle($menu_index) } 15522# ); 15523# } 15524 15525# Hierf�r nicht Autoload verwenden, weil es sonst *langsam* wird! 15526sub bikepwr_get_v { # Resultat in m/s 15527 my($wind, $i, $grade, $power_cache) = @_; 15528 if (!defined $bp_obj) { 15529 die "bp_obj ist nicht definiert"; 15530 } 15531 $grade = 0 if !defined $grade; 15532 if (defined $power_cache and 15533 exists $power_cache->{$wind}{$i}{$grade}) { 15534 return @{ $power_cache->{$wind}{$i}{$grade} }; 15535 } 15536 $bp_obj->grade($grade); 15537 $bp_obj->headwind($wind); 15538 $bp_obj->power($power[$i]); 15539 $bp_obj->calc(); 15540 my $v = $bp_obj->velocity; 15541 my $C = $bp_obj->consumption; 15542 if (defined $power_cache) { 15543 $power_cache->{$wind}{$i}{$grade} = [$v, $C]; 15544 } 15545 ($v, $C); 15546} 15547 15548# l�scht den letzten Punkt der Route aus @coords und Routenlinie 15549### AutoLoad Sub 15550sub dellast { 15551 my $no_update = shift; 15552 if (@realcoords) { 15553 if ($bikepwr) { 15554 for(my $i=0; $i <= $#power; $i++) { 15555 my $etappe_def = pop(@{$bikepwr_all_time[$i]}); 15556 if (ref $etappe_def eq 'ARRAY') { 15557 $bikepwr_time[$i] -= $etappe_def->[0]; 15558 $bikepwr_cal[$i] -= $etappe_def->[5]; 15559 } 15560 } 15561 #for(my $i=0; $i <= $#speed; $i++) { 15562 #XXX $bikepwr_cal_spd[$i] -= $etappe_def->[6]; 15563 #} 15564 } 15565 @act_search_route = (); # XXX performance hit bei langen Strecken 15566 pop @coords; 15567 my $ref = pop @realcoords; 15568 my $x = $ref->[0]; 15569 my $y = $ref->[1]; 15570 my $xy = "$x,$y"; 15571 if (@realcoords) { 15572 # F�hrstrecken ausschlie�en 15573 CHECK_NO_FERRY: { 15574 if ($net) { 15575 my $xy0 = join(",", @{$realcoords[-1]}); 15576 my $name = $net->{Net2Name}{$xy0}{$xy} || 15577 $net->{Net2Name}{$xy}{$xy0}; 15578 if (defined $name && $name =~ /^F�hre /) { 15579 last CHECK_NO_FERRY; 15580 } 15581 } 15582 15583 $strecke -= sqrt(sqr($realcoords[-1]->[0] - $x) + 15584 sqr($realcoords[-1]->[1] - $y)); 15585 } 15586 } 15587 15588 # Via l�schen, und zwar im aktuellen und im vorherigen Punkt ??? 15589 if (@search_route_points) { 15590 my $last_via = $search_route_points[-1]->[SRP_COORD]; 15591 if ($xy eq $last_via) { 15592 pop @search_route_points; 15593 } 15594 } 15595 15596 $c->delete("route-$nr"); 15597 $nr--; 15598 unless ($no_update) { 15599 update_flags_and_route(); 15600 } 15601 if ($map_mode eq MM_BUTTONPOINT) { # update also selection 15602 if (@inslauf_selection) { 15603 pop @inslauf_selection; 15604 update_clipboard(); 15605 } 15606 } 15607 check_path_in_blockings_net(\@realcoords); 15608 } 15609} 15610 15611sub update_flags_and_route { 15612 set_flag('via'); 15613 set_flag('ziel'); 15614 updatekm(); 15615 if ($map_mode eq MM_SEARCH && !@coords) { 15616 undef $search_route_flag; 15617 search_route_mouse(1); 15618 } 15619 update_route_strname(); 15620} 15621 15622### AutoLoad Sub 15623sub update_clipboard { 15624 if ($use_clipboard) { 15625 $c->clipboardClear; 15626 # Use a leading space, to be consistent with rest of (lazy) clipboard 15627 # code. 15628 $c->clipboardAppend(" " . join(" ", @inslauf_selection)); 15629 } 15630} 15631 15632# bis zum letzten Via l�schen 15633### AutoLoad Sub 15634sub deltovia { 15635 return if !@realcoords || !@search_route_points; 15636 # Zuerst wird �berpr�ft, ob der letzte Punkt ein Via-Punkt ist. In 15637 # diesem Fall wird diese Tatsache ignoriert und der Punkt wird 15638 # gel�scht. 15639 my $via = $search_route_points[-1]->[SRP_COORD]; 15640 my($x, $y) = @{ $realcoords[-1] }; 15641 my $xy = "$x,$y"; 15642 if ($xy eq $via) { 15643 dellast(); 15644 } 15645 goto CLEANUP if !@realcoords; 15646 goto CLEANUP if (!@search_route_points); 15647 $via = $search_route_points[-1]->[SRP_COORD]; 15648 for(my $i = $#realcoords; $i >= 0; $i--) { 15649 my($x, $y) = @{ $realcoords[$i] }; 15650 my $xy = "$x,$y"; 15651 if ($xy eq $via) { 15652 update_flags_and_route(); 15653 goto CLEANUP; 15654 } else { 15655 dellast(1); 15656 } 15657 } 15658 CLEANUP: 15659 update_clipboard(); 15660} 15661 15662# Ausgabe der aktuellen Routenl�nge 15663sub updatekm { 15664 return if !@realcoords; 15665 15666 my $lost_time_s; 15667 if (%ampeln) { 15668 my $ampel_count = 0; 15669 foreach (@realcoords) { 15670 if ($ampeln{$_->[0].",".$_->[1]}) { 15671 $ampel_count++; 15672 } 15673 } 15674 if ($ampel_count == 0) { 15675 $ampelstatus_label_text = M"Keine Ampeln"; 15676 } else { 15677 $lost_time_s = $ampel_count*$lost_time_per_ampel{X}; # XXX F ... 15678 $ampelstatus_label_text = 15679 "$ampel_count " . 15680 ($ampel_count > 1 ? M"Ampeln" : M"Ampel") . 15681 " (-" . s2hm_or_s($lost_time_s) . ")"; 15682 } 15683 } else { 15684 $ampelstatus_label_text = ""; 15685 } 15686 15687 my $lost_time_tragen_s = 0; 15688 my $lost_time_narrowpassage_s = 0; 15689 if (%sperre_tragen || %sperre_narrowpassage) { 15690 my $tragen_count = 0; 15691 foreach (@realcoords) { 15692 my $c = $_->[0].",".$_->[1]; 15693 if (exists $sperre_tragen{$c}) { 15694 $lost_time_tragen_s += $sperre_tragen{$c}; 15695 $tragen_count++; 15696 } elsif (exists $sperre_narrowpassage{$c}) { 15697 $lost_time_narrowpassage_s += $sperre_narrowpassage{$c}; 15698 # XXX don't count 15699 } 15700 } 15701 if ($lost_time_tragen_s) { 15702 $ampelstatus_label_text .= 15703 "\n" . 15704 Mfmt("%dx tragen", $tragen_count) . 15705 " (-" . s2hm_or_s($lost_time_tragen_s) . ")"; 15706 } 15707 } 15708 15709 my @time_h; 15710 for(my $i = 0; $i <= $#speed; $i++) { 15711 # XXX implement something similar for "power", too! 15712 if ($kopfstein_count->{"speed"}[$i]) { 15713 make_handicap_net(); 15714 make_qualitaet_net(); 15715 $time_h[$i] = 0; 15716 if ($#realcoords > 0) { 15717 for(my $ii=0; $ii<$#realcoords; $ii++) { 15718 my $s = Strassen::Util::strecke($realcoords[$ii],$realcoords[$ii+1]); 15719 my @etappe_speeds = $speed[$i]; 15720 if ($qualitaet_s_net && (my $cat = $qualitaet_s_net->{Net}{join(",",@{$realcoords[$ii]})}{join(",",@{$realcoords[$ii+1]})})) { 15721 push @etappe_speeds, $qualitaet_s_speed{$cat} 15722 if defined $qualitaet_s_speed{$cat}; 15723 } 15724 if ($handicap_s_net && (my $cat = $handicap_s_net->{Net}{join(",",@{$realcoords[$ii]})}{join(",",@{$realcoords[$ii+1]})})) { 15725 push @etappe_speeds, $handicap_s_speed{$cat} 15726 if defined $handicap_s_speed{$cat}; 15727 } 15728 $time_h[$i] += ($s/1000)/min(@etappe_speeds); 15729 } 15730 } 15731 } else { 15732 $time_h[$i] = ($strecke / 1000) / $speed[$i]; 15733 } 15734 } 15735 my $dir_strecke = 15736 sqrt(sqr($realcoords[0]->[0] - $realcoords[-1]->[0]) + 15737 sqr($realcoords[0]->[1] - $realcoords[-1]->[1])); 15738 if ($unit_s eq 'm') { 15739 $act_value{Km} = sprintf "%d", $scale_coeff * $strecke; 15740 } elsif ($unit_s eq 'mi') { 15741 $act_value{Km} = float_prec($scale_coeff * $strecke/1609.344, 1); 15742 } else { 15743 $act_value{Km} = float_prec($scale_coeff * $strecke/1000, 1); 15744 } 15745 $act_value{Percent} = ($dir_strecke != 0 15746 ? do { 15747 my $p = int(($strecke/$dir_strecke)*100)-100; 15748 # wenn 1000% erreicht sind, ist es sicher 15749 # eine Rundfahrt, und da ist eine Prozent- 15750 # angabe unsinnig 15751 $p < 1000 ? $p : ""; 15752 } 15753 : ""); 15754 for(my $i = 0; $i <= $#speed; $i++) { 15755 my $time_h = $time_h[$i] + 15756 (defined $lost_time_s && $ampel_count->{"speed"}[$i] 15757 ? $lost_time_s/3600 : 0); 15758 $time_h += ($lost_time_tragen_s+$lost_time_narrowpassage_s)/3600; 15759 my $time_s = $time_h*3600; 15760 $act_value{TimeSeconds}->[$i] = $time_s; 15761 $act_value{Time}->[$i] = s2hm_or_s($time_s); 15762 } 15763 15764 if ($bikepwr) { 15765 for(my $i = 0; $i <= $#power; $i++) { 15766 my $time = $bikepwr_time[$i] + 15767 (defined $lost_time_s && $ampel_count->{"power"}[$i] 15768 ? $lost_time_s : 0); 15769 $time += ($lost_time_tragen_s+$lost_time_narrowpassage_s)/3600; 15770 $act_value{PowerTimeSeconds}->[$i] = $time; 15771 $act_value{PowerTime}->[$i] = s2hm_or_s($time); 15772 if (!$edit_mode && !$edit_normal_mode) { 15773 $calories_power[$i] = float_prec($bikepwr_cal[$i], 1); 15774 } else { 15775 $calories_power[$i] = undef; 15776 } 15777 } 15778#XXX 15779# for(my $i = 0; $i <= $#speed; $i++) { 15780# if (!$edit_mode && !$edit_normal_mode) { 15781# $calories_speed[$i] = float_prec($bikepwr_cal_spd[$i], 1); 15782# } else { 15783# $calories_speed[$i] = undef; 15784# } 15785# } 15786 } 15787 15788 # XXX hier? 15789 Hooks::get_hooks("new_route")->execute; 15790} 15791 15792# l�scht die Route (Liste, Linie, m�gliche tempor�re Blockings) 15793sub resetroute { 15794 $strecke = 0; 15795 $act_value{Km} = ""; 15796 $act_value{Percent} = ""; 15797 for(my $i = 0; $i <= $#speed; $i++) { 15798 $act_value{TimeSeconds}->[$i] = undef; 15799 $act_value{Time}->[$i] = ""; 15800 #XXX $bikepwr_cal_spd[$i] = 0; 15801 } 15802 @realcoords = @coords = @search_route_points = (); 15803 15804 if ($bikepwr) { 15805 for(my $i = 0; $i <= $#power; $i++) { 15806 @{$bikepwr_all_time[$i]} = (); 15807 $bikepwr_time[$i] = 0; 15808 $bikepwr_cal[$i] = 0; 15809 $act_value{PowerTimeSeconds}->[$i] = undef; 15810 $act_value{PowerTime}->[$i] = ""; 15811 } 15812 } 15813 15814 $ampelstatus_label_text = ""; 15815 $c->delete('route'); 15816 $nr = -1; 15817 $next_is_undo = 0; 15818 @act_search_route = (); 15819 update_route_strname(); 15820 15821 if (@inslauf_selection || @ext_selection) { 15822 require BBBikeAdvanced; 15823 reset_selection(); 15824 } 15825} 15826 15827sub reset_undo_route { 15828 if (@realcoords) { 15829 save_route_to_register(0); 15830 } 15831 15832 resetroute(); 15833} 15834 15835### AutoLoad Sub 15836sub get_undo_route { 15837 get_route_from_register(0); 15838} 15839 15840### AutoLoad Sub 15841sub save_route_to_register { 15842 my($register) = @_; 15843 my $r = {}; 15844 $r->{RealCoords} = [@realcoords]; 15845 $r->{SearchRoutePoints} = [@search_route_points]; 15846 15847 if ($bikepwr) { 15848 for(my $i = 0; $i <= $#power; $i++) { 15849 if (defined $bikepwr_all_time[$i]) { 15850 @{ $r->{BikepwrAllTime}[$i] } = @{ $bikepwr_all_time[$i] } 15851 } 15852 $r->{BikepwrTime}[$i] = $bikepwr_time[$i]; 15853 $r->{BikepwrCal}[$i] = $bikepwr_cal[$i]; 15854 } 15855# for(my $i = 0; $i <= $#speed; $i++) { 15856# $r->{BikepwrCalSpd}[$i] = $bikepwr_cal_spd[$i]; 15857# } 15858 15859 } 15860 $r->{Nr} = $nr; 15861 15862 $save_route{$register} = $r; 15863} 15864 15865# Return false if there is no route in this register. 15866### AutoLoad Sub 15867sub get_route_from_register { 15868 my($register) = @_; 15869 if (!$save_route{$register}) { 15870 return 0; 15871 } 15872 my $r = $save_route{$register}; 15873 15874 @realcoords = @{ $r->{RealCoords} }; 15875 realcoords2coords(); 15876 @search_route_points = @{ $r->{SearchRoutePoints} }; 15877 restore_search_route_points(); 15878 15879 if ($bikepwr) { 15880 for(my $i = 0; $i <= $#power; $i++) { 15881 if (defined $r->{BikepwrAllTime}[$i]) { 15882 @{ $bikepwr_all_time[$i] } = @{ $r->{BikepwrAllTime}[$i] } 15883 } 15884 $bikepwr_time[$i] = $r->{BikepwrTime}[$i]; 15885 $bikepwr_cal[$i] = $r->{BikepwrCal}[$i]; 15886 } 15887# for(my $i = 0; $i <= $#speed; $i++) { 15888# $bikepwr_cal_spd[$i] = $r->{BikepwrCalSpd}[$i]; 15889# } 15890 } 15891 $nr = $r->{Nr}; 15892 15893 redraw_path(); 15894 update_route_strname(); 15895 15896 1; 15897} 15898 15899sub restore_search_route_points { 15900 if ($net) { 15901 for (@search_route_points) { 15902 add_new_point($net, $_->[SRP_COORD], -quiet => 1); 15903 } 15904 } 15905} 15906 15907sub set_canvas_scale { 15908 my $s = shift; 15909 $scale = $s; 15910 eval { set_canvas_scale_XS($s) }; 15911 create_transpose_subs(); 15912} 15913 15914### AutoLoad Sub 15915sub scalecanvas { 15916 my($c, $scalefactor, $x, $y, %args) = @_; 15917 my(@oldx) = $c->xview; 15918 my(@oldy) = $c->yview; 15919 my($xwidth) = $oldx[1]-$oldx[0]; 15920 my($ywidth) = $oldy[1]-$oldy[0]; 15921 my($sr_x0, $sr_y0, $sr_x1, $sr_y1) = ($Tk::VERSION == 800.017 15922 ? $c->cget(-scrollregion) 15923 : @{$c->cget(-scrollregion)}); 15924 my($rx,$ry); 15925 if (defined $x && defined $y) { 15926 ($rx, $ry) = ($c->rootx + $c->widgetx($x), 15927 $c->rooty + $c->widgety($y)); 15928 } 15929 15930 # Initialisieren (muss als erstes kommen) 15931 show_zoomrect() if $scalefactor < 1 and not $args{-fast}; 15932 15933 IncBusy($top); 15934 eval { 15935 my $old_scale = $scale; 15936 set_canvas_scale($scale * $scalefactor); 15937 $c->scale('all', 0, 0, $scalefactor, $scalefactor); 15938 calc_mapscale(); 15939 scale_width($c, $scale, $old_scale); 15940 change_category_visibility($c, $scale, $old_scale); 15941 15942 foreach (@scrollregion) { $_ *= $scalefactor } 15943 $c->configure(-scrollregion => \@scrollregion); 15944 foreach (@coords) { 15945 $_->[0] *= $scalefactor; 15946 $_->[1] *= $scalefactor; 15947 } 15948 foreach (@route_strnames) { 15949 $_->[1] *= $scalefactor; 15950 $_->[2] *= $scalefactor; 15951 } 15952 15953 scale_coords($c, $scale, $old_scale); 15954 scale_maps($scalefactor); 15955 15956 if (defined $x && defined $y) { 15957 # preserve position under cursor 15958 $c->scroll_canvasxy_to_rootxy($x*$scalefactor,$y*$scalefactor,$rx,$ry); 15959 } else { 15960 # in die Mitte des vorherigen Ausschnitts positionieren 15961 $c->xview('moveto' => $oldx[0]+($xwidth-$xwidth/$scalefactor)/2); 15962 $c->yview('moveto' => $oldy[0]+($ywidth-$ywidth/$scalefactor)/2); 15963 } 15964 15965 overview_update(); 15966 }; 15967 warn $@ if $@; 15968 DecBusy($top); 15969 15970 # Zoomrect starten 15971 show_zoomrect(1) if $scalefactor < 1 and not $args{-fast}; 15972 15973 Hooks::get_hooks("after_resize")->execute($scalefactor); 15974} 15975 15976sub scalecanvas_from_canvas_event { 15977 my($c, $scalefactor) = @_; 15978 my $e = $c->XEvent; 15979 return unless $e; 15980 my($x, $y) = ($c->canvasx($e->x), 15981 $c->canvasy($e->y)); 15982 scalecanvas($c, $scalefactor, $x, $y); 15983} 15984 15985### AutoLoad Sub 15986sub scale_width { 15987 my($c, $scale, $old_scale) = @_; 15988 15989# XXX scale obst (mehrere Icon-Gr��en) 15990 foreach my $type 15991 (qw(s-BAB sBAB-BAB s-HH s-B s-H s-NH s-N s-NN 15992 SBAB-BAB-out s-HH-out s-B-out s-H-out s-NH-out s-N-out s-NN-out 15993 rw 15994 w-W w-W0 w-W1 w-W2 w-W-out w-W0-out w-W1-out w-W2-out wr 15995 l l-out u b r pp p z g gP gD gBO fz 15996 sperre0 sperre1 sperre1s sperre2)) { 15997 eval { 15998 CHANGE: { 15999 my $new_width = get_line_width($type, $scale); 16000 if (defined $old_scale) { 16001 my $old_width = get_line_width($type, $old_scale); 16002 last CHANGE if ($new_width == $old_width); 16003 } 16004 if ($type =~ /^(sperre|fz)/) { 16005 # special handling to filter out images: 16006 foreach my $item ($c->find("withtag", $type)) { 16007 $c->itemconfigure($item, -width => $new_width) 16008 unless $c->type($item) eq 'image'; 16009 } 16010 } elsif ($type =~ /^w-.*-out$/) { 16011 foreach my $item ($c->find("withtag", $type)) { 16012 $c->itemconfigure($item, -width => $new_width) 16013 unless $c->type($item) eq 'polygon'; 16014 } 16015 } else { 16016 $c->itemconfigure($type, -width => $new_width); 16017 } 16018 } 16019 }; 16020 if ($@) { 16021 warn "Error while configuring $type in scale_width: $@"; 16022 } 16023 } 16024 foreach my $sperre_type (qw(sperre1 sperre1s sperre2)) { 16025 my $new_width = get_line_width($sperre_type); 16026 my $old_width = get_line_width($sperre_type, $old_scale); 16027 if ($new_width != $old_width) { 16028 foreach my $item ($c->find("withtag", $sperre_type)) { 16029 if ($c->type($item) ne 'image') { 16030 $c->itemconfigure 16031 ($item, 16032 -fill => ($new_width == 0 16033 ? undef : $category_color{$sperre_type})); 16034 } 16035 } 16036 } 16037 16038 ##XXX Works, but maybe it's better to put the code snippets of 16039 ##plot_sperre into strings to be evaled, used in plot_sperre 16040 ##and re-used here. 16041 # XXX adjust and move to scale_coords? 16042 if ($sperre_type =~ /^sperre[12]/) { 16043 my $new_length = get_line_length($sperre_type); 16044 my $old_length = get_line_length($sperre_type, $old_scale) * $scale/$old_scale; 16045 if ($old_length) { # XXX when may $old_length be 0? 16046 my $f = $new_length / $old_length; 16047 foreach my $item ($c->find("withtag", $sperre_type)) { 16048 if ($c->type($item) ne 'image') { 16049 my($x1,$y1,$x2,$y2) = $c->coords($item); 16050 my($xm,$ym) = (($x2+$x1)/2, ($y2+$y1)/2); 16051 my $xd1 = $x1-$xm; 16052 my $xd2 = $x2-$xm; 16053 my $yd1 = $y1-$ym; 16054 my $yd2 = $y2-$ym; 16055 $c->coords($item, 16056 $xm+$xd1*$f, $ym+$yd1*$f, 16057 $xm+$xd2*$f, $ym+$yd2*$f, 16058 ); 16059 } 16060 } 16061 } 16062 } 16063 } 16064 16065 foreach (qw(lsa-X lsa-B lsa-B0 lsa-F lsa-Zbr rest kn vf-Vf vf-Kz u b), ($XXX_use_old_R_symbol ? () : ('r'))) { 16066 $c->itemconfigure($_ . '-fg && !attrib-inwork', -image => get_symbol_scale($_, $scale)); 16067 } 16068 foreach (qw(u-U0 u-UBau b-S0 b-SBau r-R0 r-RBau r-RP)) { # overwrite the previous settings of u,b,r 16069 $c->itemconfigure($_ . '-fg', -image => get_symbol_scale($_, $scale)); 16070 } 16071 foreach (qw(attrib-inwork)) { 16072 $c->itemconfigure('attrib-inwork', -image => get_symbol_scale($_, $scale)); 16073 } 16074 foreach (qw(e comm-tram nl)) { 16075 $c->itemconfigure($_ . '-img', -image => get_symbol_scale($_, $scale)); 16076 } 16077 16078 if ($XXX_use_old_R_symbol) { 16079 # XXX ... nur �ndern, falls sich die Skalierung �ndert... (wie oben) 16080 # XXX arrowshape von sperre1 �ndern 16081 my %arg = get_symbol_scale('r'); 16082 $c->itemconfigure('r-bg', -width => $arg{-width}); 16083 $c->itemconfigure("r-fg", 16084 -text => (defined $arg{-font} ? 'R' : ''), 16085 (defined $arg{-font} ? (-font => $arg{-font}) : ()), 16086 ); 16087 } 16088 # rearrange outline_text 16089 # XXX performance is quite bad (about 0.6s for all U+S-Bahnh�fe) 16090## DEBUG_BEGIN 16091#benchbegin("Repositioning labels"); 16092## DEBUG_END 16093 # XXX adjust and move to scale_coords? 16094 foreach my $item ($c->find(withtag => 'outlmaster')) { 16095 my($x,$y) = $c->coords($item); 16096 my $outline_width = 1; 16097 my $outl_i; 16098 for ($c->gettags($item)) { 16099 if (/^outlmaster-width-(\d+)/) { 16100 $outline_width = $1; 16101 } elsif (/^outlmaster-(\d+)/) { 16102 $outl_i = $1; 16103 } 16104 } 16105 if (defined $outl_i) { 16106 # XXX the second version is a hack, but faster 16107# foreach my $slave ($c->find(withtag => "outlslave-$outl_i")) { 16108 foreach my $slave ($item-(4*$outline_width)..$item-1) { 16109 # assuming last tag is outldata_$x_$y tag 16110 my @outldata = split /_/, (($c->gettags($slave))[-1]); 16111 $c->coords($slave, $x+$outldata[1],$y+$outldata[2]); 16112 } 16113 } 16114 } 16115## DEBUG_BEGIN 16116#benchend(); 16117## DEBUG_END 16118 16119 # XXX adjust and move to scale_coords? 16120 foreach my $item ($c->find(withtag => 'strnr')) { 16121 my $master = ($c->gettags($item))[2]; 16122 $master =~ s/^strnr-//; 16123 my(@bbox) = $c->bbox($master); 16124 if ($c->type($item) eq 'image') { 16125 $c->coords($item, ($bbox[0]+$bbox[2])/2, ($bbox[1]+$bbox[3])/2); # XXX this is duplicated from draw_street_numbers! 16126 } else { 16127 $c->coords($item, $bbox[0]-2,$bbox[1]-2,$bbox[2]+2,$bbox[3]+2); 16128 } 16129 } 16130 16131 for my $o_cat (MIN_ORT_CAT .. MAX_ORT_CAT) { 16132 my $font = get_orte_label_font($o_cat); 16133 #warn "$o_cat -> " . Dumper($top->fontActual($font)) . "\n"; 16134 $c->itemconfigure("O$o_cat", -font => $font); 16135 } 16136 16137 while(my($name,$scalecommand) = each %scalecommand) { 16138 warn "Scale for $name...\n"; 16139 $scalecommand->($name, $c, $scale, $old_scale); 16140 } 16141} 16142 16143### AutoLoad Sub 16144sub scale_coords { 16145 my($c, $scale, $old_scale) = @_; 16146 16147 { 16148 my $new_width = get_line_width('comm-scenic-View', $scale); 16149 my $old_width = get_line_width('comm-scenic-View', $old_scale); 16150 if ($new_width != $old_width) { 16151 foreach my $item ($c->find(withtag => 'comm-scenic-View')) { 16152 my($cx,$cy) = Strassen::Util::middle($c->coords($item)); 16153 $c->coords($item,$cx-$new_width,$cy-$new_width,$cx+$new_width,$cy+$new_width); 16154 } 16155 } 16156 } 16157} 16158 16159### AutoLoad Sub 16160sub change_place_visibility { 16161 my($c, $new_scale) = @_; 16162 16163 # XXX genaue Version f�r dash patches rauskriegen 16164 return if $Tk::VERSION < 800.021; 16165 16166 $new_scale = $scale unless defined $new_scale; 16167 16168 if ($place_category eq 'auto') { 16169 my $eff_place_category; 16170 if ($new_scale > 0.5) { 16171 $eff_place_category = 0; 16172 } elsif ($new_scale > 0.25) { 16173 $eff_place_category = 1; 16174 } elsif ($new_scale > 0.18) { 16175 $eff_place_category = 2; 16176 } elsif ($new_scale > 0.125) { 16177 $eff_place_category = 3; 16178 } elsif ($new_scale > 0.03125) { 16179 $eff_place_category = 4; 16180 } else { 16181 $eff_place_category = 5; 16182 } 16183 16184 if ($eff_place_category > 0) { 16185 for my $cat (0 .. $eff_place_category-1) { 16186 $c->itemconfigure("O$cat", -state => "hidden"); 16187 $c->itemconfigure("OP$cat", -state => "hidden"); 16188 } 16189 } 16190 for my $cat ($eff_place_category .. 5) { 16191 $c->itemconfigure("O$cat", -state => "normal"); 16192 $c->itemconfigure("OP$cat", -state => "normal"); 16193 } 16194 } 16195} 16196 16197### AutoLoad Sub 16198sub change_label_visibility { 16199 my($c, $new_scale, $old_scale, $restrict) = @_; 16200 16201 # XXX genaue Version f�r dash patches rauskriegen 16202 return if $Tk::VERSION < 800.021; 16203 16204 $new_scale = $scale unless defined $new_scale; 16205 16206 my %tags = ('r-label' => 0.35, 16207 'b-label' => 1.5, 16208 'u-label' => 1.5, 16209 'v-fg' => 1.5, 16210 ); 16211 16212 if ($restrict) { 16213 my %new_tags; 16214 for (@$restrict) { 16215 $new_tags{$_} = $tags{$_}; 16216 } 16217 %tags = %new_tags; 16218 } 16219 16220 while(my($tag, $scale_limit) = each %tags) { 16221 if ((!defined $old_scale || $old_scale >= $scale_limit) && $new_scale <= $scale_limit) { 16222 $c->itemconfigure($tag, -state => "hidden"); 16223 } elsif ((!defined $old_scale || $old_scale < $scale_limit) && $new_scale >= $scale_limit) { 16224 $c->itemconfigure($tag, -state => "normal"); 16225 } 16226 } 16227} 16228 16229### AutoLoad Sub 16230sub change_category_visibility { 16231 my($c, $scale, $old_scale) = @_; 16232 16233 { 16234 my $new_width = get_line_width('sBAB-BAB', $scale); 16235 my $old_width = get_line_width('sBAB-BAB', $old_scale); 16236 if ($new_width != $old_width) { 16237 if ($new_width < $sBAB_two_track_width && $old_width >= $sBAB_two_track_width) { 16238 $c->itemconfigure('sBAB-fg', -state => 'hidden'); 16239 } elsif ($new_width >= $sBAB_two_track_width && $old_width < $sBAB_two_track_width) { 16240 $c->itemconfigure('sBAB-fg', -state => 'normal'); 16241 } 16242 } 16243 } 16244 16245 change_place_visibility($c, $scale); 16246 change_label_visibility($c, $scale, $old_scale); 16247 16248return 1; 16249#XXXXXXXXXXXX enable 16250# use tag_invisible for plotstr/plotp 16251# insert a checkbutton fot auto_visible 16252# str_restrict: don't set restriction on StrassenNetz 16253 for my $tag (keys %tag_visibility) { 16254 my $old_def = $tag_invisible{$tag}; 16255 if ($scale <= $tag_visibility{$tag}) { 16256 $tag_invisible{$tag} = 1; 16257 } else { 16258 $tag_invisible{$tag} = 0; 16259 } 16260 if (defined $old_def && $old_def != $tag_invisible{$tag} 16261 && $auto_visible) { 16262 if ($tag =~ /^([^-]+-[^-]+)/) { 16263 pending(1, "replot-$1"); 16264 } 16265 } 16266 } 16267} 16268 16269sub get_index_by_scale { 16270 my $myscale = shift; 16271 if ($myscale < 0.5) { 16272 0; 16273 } elsif ($myscale < 1) { 16274 1; 16275 } elsif ($myscale < 2) { 16276 2; 16277 } elsif ($myscale < 5) { 16278 3; 16279 } elsif ($myscale < 10) { 16280 4; 16281 } else { 16282 5; 16283 } 16284} 16285 16286sub get_line_width { 16287 my($tag, $myscale) = @_; 16288 $myscale = $scale if !defined $myscale; 16289 16290 my $is_outline = ($tag =~ /-out$/); 16291 my $add_outline = ($is_outline 16292 ? 2 : ($tag eq 'pp' || $tag eq 'p' ? 1 : 0)); 16293 my $index = get_index_by_scale($myscale); 16294 if ($is_outline && !exists $line_width{$tag}) { 16295 $tag =~ s/-out$//; 16296 } 16297 if ($tag =~ /^L\d+/ && 16298 defined $default_line_width && $default_line_width == 1) { 16299 1; 16300 } else { 16301 $line_width{(exists $line_width{$tag} ? $tag : 'default')}->[$index] 16302 + $add_outline; 16303 } 16304} 16305 16306sub get_line_length { 16307 my($tag, $myscale) = @_; 16308 $myscale = $scale if !defined $myscale; 16309 16310 my $index = get_index_by_scale($myscale); 16311 $line_length{(exists $line_length{$tag} ? $tag : 'default')}->[$index]; 16312} 16313 16314sub get_symbol_scale { 16315 my($tag, $myscale) = @_; 16316 $myscale = $scale if !defined $myscale; 16317 my $mod = $small_icons ? 2 : 1; 16318 if ($tag eq 'lsa-X') { 16319 if ($myscale > 4*$mod) { 16320 return $ampel_photo; 16321 } elsif ($scale >= 2*$mod) { 16322 return $ampel_klein_photo; 16323 } elsif ($scale >= 0.5*$mod) { 16324 return $ampel_klein2_photo; 16325 } else { 16326 return undef; 16327 } 16328 } elsif ($tag eq 'lsa-F') { 16329 if ($myscale > 4*$mod) { 16330 return $ampelf_photo; 16331 } elsif ($scale >= 2*$mod) { 16332 return $ampelf_klein_photo; 16333 } elsif ($scale >= 0.5*$mod) { 16334 return $ampelf_klein2_photo; 16335 } else { 16336 return undef; 16337 } 16338 } elsif ($tag =~ m{^lsa-B$}) { 16339 if ($myscale > 4*$mod) { 16340 return $andreaskr_photo; 16341 } elsif ($scale >= 2*$mod) { 16342 return $andreaskr_klein_photo; 16343 } elsif ($scale >= 0.5*$mod) { 16344 return $andreaskr_klein2_photo; 16345 } else { 16346 return undef; 16347 } 16348 } elsif ($tag =~ m{^lsa-B0$}) { 16349 if ($myscale > 4*$mod) { 16350 return $andreaskr_grey_photo; 16351 } elsif ($scale >= 2*$mod) { 16352 return $andreaskr_grey_klein_photo; 16353 } elsif ($scale >= 0.5*$mod) { 16354 return $andreaskr_grey_klein2_photo; 16355 } else { 16356 return undef; 16357 } 16358 } elsif ($tag eq 'lsa-Zbr') { 16359 if ($myscale >= 4*$mod) { 16360 return $zugbruecke_photo; 16361 } elsif ($scale >= 1*$mod) { 16362 return $zugbruecke_klein_photo; 16363 } else { 16364 return undef; 16365 } 16366 } elsif ($tag eq 'kn') { 16367 if ($myscale > 4*$mod) { 16368 return $kneipen_photo; 16369 } elsif ($scale >= 1*$mod) { 16370 return $kneipen_klein_photo; 16371 } else { 16372 return undef; 16373 } 16374 } elsif ($tag eq 'e') { 16375 if ($myscale > 2*$mod) { 16376 return $ferry_photo; 16377 } elsif ($scale >= 0.5*$mod) { 16378 return $ferry_klein_photo; 16379 } elsif ($scale >= 0.2*$mod) { 16380 return $ferry_mini_photo; 16381 } else { 16382 return undef; 16383 } 16384 } elsif ($tag eq 'rest') { 16385 if ($myscale > 4*$mod) { 16386 return $essen_photo; 16387 } elsif ($scale >= 1*$mod) { 16388 return $essen_klein_photo; 16389 } else { 16390 return undef; 16391 } 16392 } elsif ($XXX_use_old_R_symbol && $tag eq 'r') { 16393 if ($myscale > 4*$mod) { 16394 return (-width => 20, -font => "Helvetica -18"); 16395 } elsif ($myscale >= 1*$mod) { 16396 return (-width => 14, -font => ($os eq 'win' ? "Helvetica -14 bold" : "6x13bold")); 16397 } elsif ($scale >= 0.5*$mod) { 16398 return (-width => 10, -font => ($os eq 'win' ? "Helvetica -10 bold" : "5x7")); 16399 } elsif ($scale >= 0.2*$mod) { 16400 return (-width => 6, -font => undef); 16401 } else { 16402 return (-width => 3, -font => undef); 16403 } 16404 } elsif ($tag eq 'r-RP') { 16405 my $filename; 16406 if ($myscale >= 2*$mod) { 16407 $filename = 'eisenbahn_klein'; 16408 } elsif ($myscale >= 1*$mod) { 16409 $filename = 'eisenbahn_mini'; 16410 } 16411 if ($filename) { 16412 return load_photo($top, $filename, -persistent => 1); 16413 } else { 16414 return undef; 16415 } 16416 } elsif ($tag eq 'r' || $tag eq 'r-R0') { 16417 my $filename; 16418 if ($myscale > 2*$mod) { 16419 $filename = 'eisenbahn' 16420 } elsif ($myscale >= 0.5*$mod) { 16421 $filename = 'eisenbahn_klein'; 16422 } elsif ($myscale >= 0.2*$mod) { 16423 $filename = 'eisenbahn_mini'; 16424 } 16425 my $photo; 16426 if ($filename) { 16427 if ($tag eq 'r-R0') { 16428 $filename =~ s{(eisenbahn)}{$1_stillg}; 16429 } 16430 $photo = load_photo($top, $filename, -persistent => 1); 16431 } 16432 return $photo; 16433 } elsif ($tag eq 'u' || $tag eq 'b' || $tag eq 'u-U0' || $tag eq 'b-S0' || $tag eq 'u-UBau' || $tag eq 'b-SBau') { 16434 my $photo; 16435 my $base = $tag =~ m{^b} ? "sbahn" : "ubahn"; 16436 my $filename; 16437 if ($myscale > 2*$mod) { 16438 $filename = $base; 16439 } elsif ($myscale >= 0.5*$mod) { 16440 $filename = $base . "_klein"; 16441 } elsif ($myscale >= 0.2*$mod) { 16442 $filename = $base . "_mini"; 16443 } 16444 if ($filename) { 16445 if ($tag =~ m{^[ub]-[US](0|Bau)$}) { 16446 $photo = load_photo($top, $filename, -persistent => 1, -palette => 256, -gamma => 3); 16447 } else { 16448 $photo = load_photo($top, $filename, -persistent => 1); 16449 } 16450 } 16451 return $photo; 16452 } elsif ($tag eq 'vf-Vf') { 16453 if ($myscale > 2*$mod) { 16454 $vorfahrt_photo = load_photo($top, 'vorfahrt') if !$vorfahrt_photo; 16455 return $vorfahrt_photo; 16456 } elsif ($scale >= 0.5*$mod) { 16457 $vorfahrt_klein_photo = load_photo($top, 'vorfahrt_klein') if !$vorfahrt_klein_photo; 16458 return $vorfahrt_klein_photo; 16459 } else { 16460 return undef; 16461 } 16462 } elsif ($tag eq 'vf-Kz') { 16463 if ($myscale > 2*$mod) { 16464 $kreuzung_photo = load_photo($top, 'kreuzung') if !$kreuzung_photo; 16465 return $kreuzung_photo; 16466 } elsif ($scale >= 0.5*$mod) { 16467 $kreuzung_klein_photo = load_photo($top, 'kreuzung_klein') if !$kreuzung_klein_photo; 16468 return $kreuzung_klein_photo; 16469 } else { 16470 return undef; 16471 } 16472 } elsif ($tag eq 'comm-tram') { 16473 my $filename; 16474 if ($myscale > 4*$mod) { 16475 $filename = 'strassenbahn' 16476 } elsif ($myscale >= 1*$mod) { 16477 $filename = 'strassenbahn_klein'; 16478 } 16479 my $photo; 16480 if ($filename) { 16481 $photo = load_photo($top, $filename, -persistent => 1); 16482 } 16483 return $photo; 16484 } elsif ($tag eq 'nl') { 16485 my $photo; 16486 if ($myscale > 8*$mod) { 16487 $photo = $night_photo; 16488 } elsif ($myscale >= 2*$mod) { 16489 my $filename = 'night_klein'; 16490 $photo = load_photo($top, $filename, -persistent => 1); 16491 } 16492 return $photo; 16493 } elsif ($tag eq 'attrib-inwork') { 16494 my $photo; 16495 if ($myscale > 4*$mod) { 16496 $photo = $inwork_photo; 16497 } elsif ($myscale >= 2*$mod) { 16498 $photo = $inwork_klein_photo; 16499 } 16500 return $photo; 16501 } 16502} 16503 16504sub scale_maps { 16505 my $scalefactor = shift; 16506 if (defined $map_img || @map_surround_img) { 16507 my($width, $height); 16508 for my $img ($map_img, @map_surround_img) { 16509 if (defined $img) { 16510 ($width, $height) = ($img->width, $img->height); 16511 last; 16512 } 16513 } 16514 if (defined $width) { 16515 my @maps = $c->find(withtag => 'map'); 16516 for my $map_i (@maps) { 16517 my @map_coords = $c->coords($map_i); 16518 if ($c->type($map_i) eq 'image') { 16519 eval { 16520 my $p = $c->itemcget($map_i, "-image"); 16521 $p->delete; 16522 }; warn $@ if $@; 16523 } 16524 $c->delete($map_i); 16525 @map_coords = ($map_coords[0]+$width*$scalefactor/2, 16526 $map_coords[1]+$height*$scalefactor/2); 16527 # @map_coords zeigt jetzt auf die Mitte der Karte ... 16528 eval { 16529 local $map_surround = 0; 16530 getmap(@map_coords); # Karte neu zeichnen (richtig skaliert) 16531 }; warn $@ if $@; 16532 } 16533 } 16534 } 16535} 16536 16537sub scrollregion_best { 16538 if ($city_obj->bbox) { 16539 require BBBikeAdvanced; 16540 set_scrollregion(@{ $city_obj->_bbox_standard_coordsys }); 16541 } 16542} 16543 16544# Zentriert entweder auf eine Stra�e oder Koordinaten oder auf die Mitte 16545# Berlins. 16546### AutoLoad Sub 16547sub center_best { 16548 if (defined $city && $city eq 'Berlin') { 16549 if (defined $center_on_str && $center_on_str !~ /^\s*$/) { 16550 choose_from_plz(-str => $center_on_str); 16551 return; 16552 } elsif (defined $center_on_coord && $center_on_coord !~ /^\s*$/) { 16553 choose_from_plz(-coord => $center_on_coord); 16554 return; 16555 } 16556 } 16557 if ($city_obj->_center_standard_coordsys) { 16558 $c->center_view(transpose(split /,/, $city_obj->_center_standard_coordsys)); 16559 } elsif ($city_obj->center) { 16560 $c->center_view(transpose(split /,/, $city_obj->center)); 16561 } else { 16562 $c->center_view; 16563 } 16564} 16565 16566# Zentriert auf den Anfang der aktuellen Route 16567### AutoLoad Sub 16568sub center_begin_of_route { 16569 $c->center_view($coords[0]->[0], $coords[0]->[1]); 16570} 16571 16572# Zentriert auf den Anfang der aktuellen Route und verschiebt zum 16573# letzten Punkt der Route hin, 16574### AutoLoad Sub 16575sub center_whole_route { 16576 $c->see($coords[0]->[0], $coords[0]->[1], 16577 $coords[-1]->[0], $coords[-1]->[1], 16578 ); 16579} 16580 16581# Zoomt den Ausschnitt so, da� minx/miny und maxx/maxy in den Ecken stehen. 16582# Wenn keine Argumente angegeben sind, werden die Minimal/Maximalwerte der 16583# aktuellen Route genommen. 16584### AutoLoad Sub 16585sub zoom_view { 16586 my($minx, $miny, $maxx, $maxy); 16587 if (@_) { 16588 ($minx, $miny, $maxx, $maxy) = @_; 16589 } elsif (!@coords) { 16590 return; 16591 } else { 16592 foreach (@coords) { 16593 if (!defined $minx || $_->[0] < $minx) { $minx = $_->[0] } 16594 if (!defined $maxx || $_->[0] > $maxx) { $maxx = $_->[0] } 16595 if (!defined $miny || $_->[1] < $miny) { $miny = $_->[1] } 16596 if (!defined $maxy || $_->[1] > $maxy) { $maxy = $_->[1] } 16597 } 16598 } 16599 16600 my(@corner) = $c->get_corners; 16601 my $c_w = ($corner[2]-$corner[0]); 16602 my $c_h = ($corner[3]-$corner[1]); 16603 my($r_w, $r_h) = ($maxx-$minx, $maxy-$miny); 16604 $c->center_view($r_w/2+$minx, $r_h/2+$miny); 16605 # XXX ls/pt-Version 16606 if ($r_w > 0 and $r_h > 0) { 16607 my $asp_x = $c_w/$r_w; 16608 my $asp_y = $c_h/$r_h; 16609 if ($asp_x < $asp_y) { 16610 scalecanvas($c, $asp_x/1.1); # 10% Luft lassen 16611 } else { 16612 scalecanvas($c, $asp_y/1.1); 16613 } 16614 } 16615} 16616 16617# XXX move to CanvasUtil.pm ??? 16618sub Tk::Canvas::smooth_scroll { 16619 my($c, $tox, $toy, %args) = @_; 16620 if ($use_smooth_scroll && !$args{NoSmoothScroll}) { 16621 my($fromx, $fromy) = (($c->xview)[0], ($c->yview)[0]); 16622 my $step = 10; 16623 my($deltax, $deltay) = (($tox-$fromx)/$step, 16624 ($toy-$fromy)/$step); 16625 for (1 .. $step) { 16626 $c->xview('moveto' => $fromx + $deltax * $_); 16627 $c->yview('moveto' => $fromy + $deltay * $_); 16628 $c->idletasks; 16629 } 16630 } else { 16631 $c->xview('moveto' => $tox); 16632 $c->yview('moveto' => $toy); 16633 } 16634} 16635 16636# Diese Funktion geht von einer korrekten dpi-Einstellung f�r den 16637# Bildschirm und quadratischen Dots aus. 16638# R�ckgabewert: Der Teil hinter dem Doppelpunkt. 16639sub calc_mapscale_nenner { 16640 my($mx1) = transpose(0, 0); 16641 my($mx2) = transpose(1000, 1000); 16642 my $nenner = (($mx2-$mx1)/$top_dpmm/$scale_coeff); 16643 if ($nenner == 0) { $nenner = 0.00000001 } 16644 $nenner = abs(int(1_000_000 / $nenner)); 16645 $nenner; 16646} 16647 16648# side-effect: this also sets $mapscale 16649sub calc_mapscale { 16650 my $nenner = calc_mapscale_nenner(); 16651 $mapscale = "1:$nenner"; 16652 $nenner; 16653} 16654 16655### AutoLoad Sub 16656sub show_zoomrect { 16657 my($i) = @_; 16658 if (!defined $i) { 16659 $c->delete('zoomrect'); 16660 if (defined $zoomrect_after) { 16661 $zoomrect_after->cancel; 16662 } 16663 my @c = $c->get_corners; 16664 $c->createLine(@c[0,1, 0,3, 2,3, 2,1, 0,1], 16665 -tags => 'zoomrect', 16666 ); 16667 } elsif ($i > 3*2) { 16668 $c->delete('zoomrect'); 16669 undef $zoomrect_after; 16670 } else { 16671 $c->itemconfigure('zoomrect', 16672 -fill => ($i % 2 == 1 ? 'blue' : 'red')); 16673 $zoomrect_after = $c->after(300, sub { show_zoomrect($i+1) }); 16674 } 16675} 16676 16677# Mark blinking is only implemented in the main canvas, 16678# not the overview canvas 16679### AutoLoad Sub 16680sub show_mark { 16681 my($i, %args) = @_; 16682 $i = 0 if !defined $i; 16683 if ($i == 0 and $showmark_after) { 16684 $showmark_after->cancel; 16685 undef $showmark_after; 16686 } 16687 my @stipple = ('gray12', 'gray25', 'gray50', 'gray75'); 16688 my $col = $i/8; # color ... 16689 my $j = $i%8; # stage ... 16690 if ($col > 5 && !$args{'-endlessmark'}) { 16691 $c->delete('show'); 16692 undef $showmark_after; 16693 } else { 16694 $c->itemconfigure('show', 16695 -fill => ($col % 2 == 1 ? 'blue' : 'red')); 16696 if ($j < 4) { 16697 $c->itemconfigure('show', 16698 -stipple => $stipple[$j]); 16699 } elsif ($j == 4) { 16700 $c->itemconfigure('show', 16701 -stipple => undef); 16702 } else { 16703 $c->itemconfigure('show', 16704 -stipple => $stipple[8-$j]); 16705 } 16706 unless ($steady_mark) { 16707 $showmark_after = $c->after(150, sub { show_mark($i+1, %args) }); 16708 } else { 16709 $c->itemconfigure('show', 16710 -stipple => undef); 16711 } 16712 } 16713} 16714 16715## DEBUG_BEGIN 16716#BEGIN{mymstat("75% BEGIN");} 16717## DEBUG_END 16718 16719### AutoLoad Sub 16720sub show_overview { 16721 my $new = shift; 16722 16723 my $overview_top = $toplevel{"overview"}; 16724 16725 if ($overview_top && $overview_top->{CoordSystem} ne $coord_system) { 16726 $new = 1; 16727 } 16728 if (defined $overview_top and Tk::Exists($overview_top)) { 16729 if ($new) { 16730 $overview_top->destroy; 16731 delete $toplevel{"overview"}; 16732 } 16733 } 16734 16735 if (defined $overview_top && Tk::Exists($overview_top)) { 16736 if (!$show_overview) { 16737 $overview_top->withdraw; 16738 } else { 16739 $overview_top->deiconify; 16740 $overview_top->raise; 16741 } 16742 return; 16743 } 16744 16745 $overview_top = $top->Toplevel(-title => M"�bersicht", 16746 -class => "Bbbike Overview", 16747 ); 16748 $overview_top->OnDestroy(sub { $show_overview = 0; }); 16749 $toplevel{"overview"} = $overview_top; 16750 set_as_toolwindow($overview_top); 16751 $overview_top->{CoordSystem} = $coord_system; 16752 { 16753 # Try to set the overview to the right bottom corner of the main 16754 # window: 16755 my($w,$h) = (int($top->width/3), int($top->height/3)); 16756 # restrict aspect to 4:3 --- a 16:9 overview window does not look good 16757 $w = min($w, int($h*4/3)); 16758 my($x,$y) = ($sy->rootx - $w - 4*2, $sx->rooty - $h - 20 - 4); 16759 geometry($overview_top,$x,$y,$w,$h); 16760 } 16761 show_overview_populate($overview_top); 16762} 16763 16764sub show_overview_clean_and_populate { 16765 my $overview_top = shift; 16766 for ($overview_top->children) { 16767 $_->destroy; 16768 } 16769 show_overview_populate($overview_top); 16770} 16771 16772sub overview_draw_route { 16773 if (Tk::Exists($overview_canvas)) { 16774 my $transpose = $show_overview_mode eq 'region' ? \&transpose_small : \&transpose_medium; 16775 $overview_canvas->delete("route"); 16776 return if !@realcoords; 16777 my @coords = map { $transpose->(@$_) } @realcoords; 16778 if (@coords == 2) { 16779 push @coords, @coords; 16780 } 16781 $overview_canvas->createLine(@coords, 16782 -fill => "red", -tags => "route"); 16783 } 16784} 16785 16786sub overview_del_route { 16787 if (Tk::Exists($overview_canvas)) { 16788 $overview_canvas->delete("route"); 16789 } 16790} 16791 16792sub _convert_transposed_to_overview_coord { 16793 my($tx,$ty) = @_; 16794 my $transpose = $show_overview_mode eq 'region' ? \&transpose_small : \&transpose_medium; 16795 $transpose->(anti_transpose($tx, $ty)); 16796} 16797 16798sub _convert_overview_to_transposed_coord { 16799 my($x,$y) = @_; 16800 my $anti_transpose = $show_overview_mode eq 'region' ? \&anti_transpose_small : \&anti_transpose_medium; 16801 $anti_transpose->(transpose($x, $y)); 16802} 16803 16804sub show_overview_populate { 16805 my $overview_top = shift; 16806 my $withdraw_sub = sub { $overview_top->withdraw; 16807 $show_overview = 0 }; 16808 $overview_top->protocol('WM_DELETE_WINDOW', $withdraw_sub); 16809 16810 # Canvas. Create scrollbars manually, so arrow_update can be called 16811 $overview_canvas = $overview_top->Canvas 16812 (-xscrollincrement => 15, # XXX check values 16813 -yscrollincrement => 15, 16814 -bg => $map_bg, 16815 ); 16816 16817 Hooks::get_hooks("new_route")->add 16818 (sub { 16819 overview_draw_route(); 16820 }, "bbbike-overviewcanvas"); 16821 Hooks::get_hooks("del_route")->add 16822 (sub { 16823 overview_del_route(); 16824 }, "bbbike-overviewcanvas"); 16825 $overview_canvas->OnDestroy 16826 (sub { 16827 for my $hook ("new_route", "del_route") { 16828 Hooks::get_hooks($hook)->del("bbbike-overviewcanvas"); 16829 } 16830 }); 16831 16832 my $ov_transpose = $show_overview_mode eq 'region' ? \&transpose_small : \&transpose_medium; 16833 my $ov_anti_transpose = $show_overview_mode eq 'region' ? \&anti_transpose_small : \&anti_transpose_medium; 16834 { 16835 my($x0,$y0,$x1,$y1) = @scrollregion; 16836 ($x0,$y0) = $ov_transpose->(anti_transpose($x0,$y0)); 16837 ($x1,$y1) = $ov_transpose->(anti_transpose($x1,$y1)); 16838 my @s = ($x0,$y0,$x1,$y1); 16839 $overview_canvas->configure(-scrollregion => [@s]); 16840 } 16841 16842 $overview_canvas->createLine(0,0,0,0,-fill => 'red', -tags => 'zoomrect'); 16843 $overview_top->gridColumnconfigure(0, -weight => 1); 16844 $overview_top->gridRowconfigure(0, -weight => 1); 16845 $overview_canvas->grid(-row => 0, -column => 0, -sticky => 'eswn'); 16846 my $sy = $overview_top->Scrollbar(-command => ["yview", $overview_canvas]); 16847 $sy->grid(-row => 0, -column => 1, -sticky => 'ns'); 16848 my $sx = $overview_top->Scrollbar(-orient => 'horiz', 16849 -command => ["xview", $overview_canvas]); 16850 $sx->grid(-row => 1, -column => 0, -sticky => 'ew'); 16851 16852 my $center_coords; 16853 if ($city_obj->center) { 16854 $center_coords = [ split /,/, $city_obj->center ]; 16855 } else { 16856 $center_coords = [8581,12243]; # Fallback: Brandenburger Tor 16857 } 16858 16859 my($ov_center_x,$ov_center_y) = $ov_transpose->(@$center_coords); 16860 16861 my $center_name; 16862 if ($city_obj->center_name) { 16863 $center_name = $city_obj->center_name; 16864 } 16865 16866 my $arrow_update; 16867 if ($center_name) { 16868 $arrow_update = sub { 16869 $overview_canvas->delete('berlinarrow'); 16870 my($cx1,$cy1,$cx2,$cy2) = $overview_canvas->get_corners; 16871 # Ersten Schnittpunkt (inneres Rechteck) ermitteln 16872 my($ix1,$iy1) = VectorUtil::intersect_line_rectangle 16873 ($cx1+($cx2-$cx1)/2, $cy1+($cy2-$cy1)/2, $ov_center_x,$ov_center_y, 16874 $cx1+15,$cy1+15,$cx2-15,$cy2-15); 16875 if (defined $ix1 and defined $iy1) { 16876 # zweiten Schnittpunkt ermitteln (aktuelle Canvasgrenze) 16877 my($ix2,$iy2) = VectorUtil::intersect_line_rectangle($ix1,$iy1,$ov_center_x,$ov_center_y, 16878 $cx1,$cy1,$cx2,$cy2); 16879 if (defined $ix2 and defined $iy2) { 16880 # Distance to center (in Berlin: Brandenburger Tor) 16881 my $entf = Strassen::Util::strecke 16882 ([$ov_anti_transpose->($ix1,$iy1)], 16883 $center_coords); 16884 $overview_canvas->createLine 16885 ($ix1,$iy1,$ix2,$iy2, 16886 -arrow => "last", 16887 -width => 2, 16888 -fill => "red", 16889 -tags => 'berlinarrow'); 16890 $overview_canvas->createText 16891 ($ix1, $iy1, 16892 -anchor => BBBikeCalc::canvas_translation(BBBikeCalc::line_to_canvas_direction 16893 ($ix1,$iy1,$ix2,$iy2)), 16894 -text => "$center_name\n".sprintf("%d km", $entf/1000), 16895 -fill => "red", 16896 -font => $font{'small'}, 16897 -tags => ['berlinarrow','berlinarrowlabel']); 16898 } 16899 } 16900 }; 16901 } else { 16902 $arrow_update = sub {}; 16903 } 16904 16905 $overview_canvas->configure(-yscrollcommand => 16906 sub { 16907 $sy->set(@_); 16908 $arrow_update->(); 16909 }, 16910 -xscrollcommand => 16911 sub { 16912 $sx->set(@_); 16913 $arrow_update->(); 16914 }, 16915 ); 16916 16917 # Zoom buttons 16918 my $button_x = 2; 16919 { 16920 my @zoom_button; 16921 my $set_disabled_buttons = sub { 16922 if ($show_overview_mode eq 'city') { 16923 $zoom_button[0]->configure(-state => 'disabled'); 16924 $zoom_button[1]->configure(-state => 'normal'); 16925 } else { 16926 $zoom_button[0]->configure(-state => 'normal'); 16927 $zoom_button[1]->configure(-state => 'disabled'); 16928 } 16929 }; 16930 for my $def (['+', 'city'], 16931 ['-', 'region'], 16932 ) { 16933 my($label, $overview_mode_value) = @$def; 16934 push @zoom_button, $overview_top->Button 16935 (-text => $label, 16936 -font => $font{'reduced'}, 16937 -padx => 0, -pady => 0, 16938 -highlightthickness => 0, 16939 -takefocus => 0, 16940 -command => sub { 16941 my $this_button = shift; 16942 $show_overview_mode = $overview_mode_value; 16943 $overview_top->after(10, sub { show_overview_clean_and_populate($overview_top) }); 16944 $set_disabled_buttons->(); 16945 }, 16946 ); 16947 $zoom_button[-1]->place("-x" => $button_x, "-y" => 2); 16948 $button_x += $zoom_button[-1]->reqwidth+2; 16949 } 16950 $set_disabled_buttons->(); 16951 } 16952 16953 my($km100_pixel) = ($ov_transpose->(100000,0))[0] - ($ov_transpose->(0,0))[0]; 16954 16955 # Radar button 16956 if ($advanced && $devel_host) { 16957 my $radar_onoff = 0; 16958 my $radar_button; 16959 my $show_radar_image; 16960 $radar_button = $overview_top->Checkbutton 16961 (-font => $font{'small'}, 16962 -indicatoron => 0, 16963 -padx => 0, 16964 -pady => ($os eq 'win' ? 0 : 1), # for Checkbuttons 1, for Buttons 0 (why?) 16965 -highlightthickness => 0, 16966 -takefocus => 0, 16967 -text => 'Radar', 16968 -variable => \$radar_onoff, 16969 -command => sub { 16970 $radar_button->after(50, $show_radar_image); 16971 } 16972 ); 16973 $show_radar_image = sub { 16974 if ($radar_image) { 16975 eval q{ $radar_image->delete }; 16976 } 16977 $overview_canvas->delete('radarimage'); 16978 return if !$radar_onoff; 16979 16980 IncBusy($top); 16981 $progress->Init(-label => M"Radarschirm"); 16982 eval { 16983 require FURadar; 16984 $FURadar::progress = $progress; 16985 $FURadar::VERBOSE = $verbose; 16986 # $FURadar::use_map = ($show_overview_mode eq 'region' 16987 # ? 'FURadar2' : 'FURadar'); 16988 $FURadar::use_map = 'FURadar2'; # the only left... 16989 # XXXX use fetch and cache routine 16990 my $origimgfile = FURadar::fetch(); 16991 #XXX my $origimgfile = FURadar::latest_dwd(); 16992 if ($origimgfile) { 16993 my $time = (stat($origimgfile))[STAT_MODTIME]; 16994 my $imgfile = FURadar::interesting_parts 16995 ($origimgfile, 16996 -km100pixel => $km100_pixel); 16997 if (-r $imgfile) { 16998 $radar_image = $overview_canvas->Photo(-file => $imgfile); 16999 my($xoff,$yoff) = ($show_overview_mode eq 'region' 17000 ? (3,20) 17001 : $ov_transpose->(0,0)); 17002 $overview_canvas->createImage 17003 ($xoff, $yoff, 17004 -image => $radar_image, 17005 -tags => 'radarimage'); 17006 foreach my $raise (qw(g gP gD gBO O o)) { # XXX evtl. andere Tags auch raisen 17007 $overview_canvas->raise($raise); 17008 } 17009 } 17010 if ($time) { 17011 $balloon->attach($radar_button, 17012 -msg => scalar localtime $time); 17013 } 17014 } 17015 }; 17016 warn __LINE__ . ": $@" if $@; 17017 $progress->Finish; 17018 DecBusy($top); 17019 }; 17020 $radar_button->configure(-selectcolor => $radar_button->cget(-background)); 17021 $radar_button->place("-x" => $button_x+2, "-y" => 2); 17022 } 17023 17024 my @layer_errors; 17025 17026 # Zeichnen von Gew�ssern, S-Bahnen, Regionalbahnen, Stra�en 17027 # in der �bersichtskarte 17028 foreach my $abk (qw(w b s l r)) { 17029 eval { 17030 local %str_outline = %{ clone \%str_outline }; 17031 local %str_name_draw = %{ clone \%str_name_draw }; 17032 local $wasserumland = $wasserumland; 17033 local $wasserstadt = $wasserstadt; 17034 local %str_far_away = %{ clone \%str_far_away }; 17035 local %str_restrict = %{ clone \%str_restrict }; 17036 local %p_draw = %{ clone \%p_draw }; 17037 if ($overview_draw{$abk} || ($abk eq 'l' && $overview_draw{'s'})) { 17038 $str_outline{$abk} = 0; 17039 $p_draw{'pp'} = 0; 17040 my %args; 17041 if ($abk eq 'w') { 17042 my $ws_low = eval { Strassen->new("wasserstrassen-lowres") }; 17043 if ($ws_low) { 17044 $args{-object} = $ws_low; 17045 } else { 17046 for my $cat (qw(W1 W2 F:W F:I)) { 17047 $str_restrict{$abk}->{$cat} = 1; 17048 } 17049 for my $cat (qw(W0 W)) { 17050 $str_restrict{$abk}->{$cat} = 0; 17051 } 17052 $wasserumland = $wasserstadt = 1; 17053 $str_far_away{$abk} = 1; 17054 } 17055 $str_name_draw{$abk} = 0; 17056 } elsif ($abk eq 's' || $abk eq 'l') { 17057 $str_restrict{$abk} = {qw(HH 1 B 1 H 0)}; # XXX bad bad hack. The H=>0 is necessary too trigger $all_set=0 elsewhere XXX 17058 } 17059 17060 plot('str',$abk, 17061 Canvas => $overview_canvas, 17062 Width => 1, 17063 %args, 17064 ); 17065 17066 if ($abk eq 'w') { 17067 # Hack: need to display islands over water 17068 $overview_canvas->raise('i-I'); 17069 } 17070 } 17071 }; 17072 if ($@) { 17073 push @layer_errors, "Der Layer <$abk> kann nicht gezeichnet werden: $@"; 17074 } 17075 } 17076 17077 overview_draw_route(); 17078 17079 $progress->InitGroup; 17080 for my $abk (qw(g gD)) { 17081 eval { 17082 plot('str',$abk, 17083 Canvas => $overview_canvas, 17084 ($abk eq 'g' && $coord_system ne 'standard' ? (Filename => "plz-orig") : ()), 17085 Width => 3, 17086 ); 17087 }; 17088 if ($@) { 17089 push @layer_errors, "Der Layer mit den Grenzen <$abk> kann nicht gezeichnet werden: $@"; 17090 } 17091 } 17092 17093 eval { 17094 # local does not work here, segfault on Win98+perl5.6.1/perl5.8.0+Tk800.0xx 17095 my $orte_far_away_orig = $p_far_away{'o'}; 17096 $p_far_away{'o'} = 1; 17097 my $no_overlap_label_orig = $no_overlap_label{'o'}; 17098 $no_overlap_label{'o'} = 1; # XXX Kein Effekt - warum? 17099 my $orte_label_size_orig = $orte_label_size; 17100 $orte_label_size = 1; 17101 if ($city_obj->is_osm_source) { 17102 # The PlaceCategory=2/3 limit works good for Dalmatia, 17103 # but is a little bit slow and to dense for Hessen and Sachsen 17104 plotorte(Canvas => $overview_canvas, 17105 PlaceCategory => $show_overview_mode eq 'city' ? 2 : 3, 17106 Shortname => 1, 17107 NoOverlapLabel => 'drop_non_fitting', 17108 ); 17109 } else { 17110 # the old procedure for Berlin data 17111 plotorte(Canvas => $overview_canvas, 17112 PlaceCategory => 4, 17113 Shortname => 1, 17114 NoOverlapLabel => 0, 17115 ); 17116 if ($show_overview_mode eq 'city') { 17117 plotorte(Canvas => $overview_canvas, 17118 PlaceCategory => 0, 17119 Shortname => 1, 17120 NameDraw => 1, 17121 -municipality => 1, 17122 -type => 'oo' 17123 ); 17124 } 17125 } 17126 17127 $p_far_away{'o'} = $orte_far_away_orig; 17128 $orte_label_size = $orte_label_size_orig; 17129 $no_overlap_label{'o'} = $no_overlap_label_orig; 17130 }; 17131 if ($@) { 17132 push @layer_errors, "Der Orte-Layer kann nicht gezeichnet werden: $@"; 17133 } 17134 17135 $progress->FinishGroup; 17136 17137 if (@layer_errors) { 17138 status_message(join("\n", @layer_errors), "warn"); 17139 } 17140 17141 $overview_canvas->raise("zoomrect"); 17142 $overview_top->bind('<q>' => $withdraw_sub); 17143 $overview_top->bind('<Q>' => sub { &$withdraw_sub; 17144 $overview_top->destroy 17145 }); 17146 my $real_canvas = $overview_canvas; 17147 my $scroll_lock; 17148 my $set_scroll_lock = sub { 17149 $scroll_lock = $overview_canvas->after(100, 17150 sub { undef $scroll_lock }); 17151 }; 17152 my $button_pressed; 17153 my $refresh_sub; 17154 my($delta_x_fraction, $delta_y_fraction) = (0.5, 0.5); 17155 $refresh_sub = 17156 sub { 17157 my($w, $initial) = @_; 17158 my $e = $w->XEvent; 17159 if (!defined $button_pressed) { 17160 $button_pressed = $overview_canvas->repeat 17161 (100, sub { $refresh_sub->($w, 0); }); 17162 } 17163 return if $scroll_lock; 17164 my($x, $y) = ($e->x, $e->y); 17165 my($xx, $yy) = ($overview_canvas->canvasx($x), 17166 $overview_canvas->canvasy($y)); 17167 if ($initial) { 17168 my(@c) = $overview_canvas->bbox('zoomrect'); 17169 if ($xx >= $c[0] && $xx <= $c[2] && 17170 $yy >= $c[1] && $yy <= $c[3]) { 17171 # Click in rect, record initial position. 17172 # This code is necessary to avoid jumps on initial click. 17173 $delta_x_fraction = ($xx-$c[0])/($c[2]-$c[0]); 17174 $delta_y_fraction = ($yy-$c[1])/($c[3]-$c[1]); 17175 } 17176 } 17177 my $real_canvas_width = $real_canvas->width; 17178 my $real_canvas_height = $real_canvas->height; 17179 # XXX ist noch etwas ruckartig ... kleinere units, 17180 # intelligenteres Handling! 17181 my $pad = 10; 17182 if ($x < $pad) { 17183 $overview_canvas->xview(scroll => -1, 'units'); 17184 $set_scroll_lock->(); 17185 } 17186 if ($y < $pad) { 17187 $overview_canvas->yview(scroll => -1, 'units'); 17188 $set_scroll_lock->(); 17189 } 17190 if ($x > $real_canvas_width-$pad) { 17191 $overview_canvas->xview(scroll => +1, 'units'); 17192 $set_scroll_lock->(); 17193 } 17194 if ($y > $real_canvas_height-$pad) { 17195 $overview_canvas->yview(scroll => +1, 'units'); 17196 $set_scroll_lock->(); 17197 } 17198 my(@oldx) = $c->xview; 17199 my(@oldy) = $c->yview; 17200 my($xwidth) = $oldx[1]-$oldx[0]; 17201 my($ywidth) = $oldy[1]-$oldy[0]; 17202 17203 ($xx, $yy) = ($show_overview_mode eq 'region' 17204 ? anti_transpose_small($xx, $yy) 17205 : anti_transpose_medium($xx, $yy) 17206 ); 17207 ($xx, $yy) = transpose($xx, $yy); 17208 $c->center_view($xx,$yy); 17209 }; 17210 17211 $real_canvas->Tk::bind('<ButtonPress-1>' => sub { 17212 my $w = shift; 17213 $refresh_sub->($w, 1, @_) 17214 }); 17215 $real_canvas->Tk::bind('<B1-Motion>' => sub { 17216 my $w = shift; 17217 $refresh_sub->($w, 0, @_) 17218 }); 17219 $real_canvas->Tk::bind 17220 ('<ButtonRelease-1>' 17221 => sub { 17222 if (defined $button_pressed) { 17223 $button_pressed->cancel(); 17224 undef $button_pressed; 17225 } 17226 ($delta_x_fraction, $delta_y_fraction) = (0.5, 0.5); 17227 }); 17228 17229 { 17230 my $gain = 1; 17231 $real_canvas->CanvasBind('<2>', 17232 [sub { 17233 my($w,$x,$y) = @_; 17234 $w->scan('mark',$x,$y); 17235 },Tk::Ev('x'),Tk::Ev('y')]); 17236 $real_canvas->CanvasBind('<B2-Motion>', 17237 [sub { 17238 my($w,$x,$y) = @_; 17239 $w->scan('dragto',$x,$y,$gain); 17240 },Tk::Ev('x'),Tk::Ev('y')]); 17241 } 17242 17243 # Scrolling korrigieren (auf Mitte setzen) 17244 my(@oldx) = $overview_canvas->xview; 17245 my(@oldy) = $overview_canvas->yview; 17246 my($xwidth) = $oldx[1]-$oldx[0]; 17247 my($ywidth) = $oldy[1]-$oldy[0]; 17248 $overview_canvas->xview('moveto' => (1-$xwidth)/2); 17249 $overview_canvas->yview('moveto' => (1-$ywidth)/2); 17250 17251 overview_update(); 17252 17253 # Scrollbar-Navigation per Cursortasten 17254 $overview_top->bind 17255 ('<Up>' => sub { $real_canvas->yview(scroll => -1, 'units') }); 17256 $overview_top->bind 17257 ('<Down>' => sub { $real_canvas->yview(scroll => 1, 'units') }); 17258 $overview_top->bind 17259 ('<Left>' => sub { $real_canvas->xview(scroll => -1, 'units') }); 17260 $overview_top->bind 17261 ('<Right>' => sub { $real_canvas->xview(scroll => 1, 'units') }); 17262} 17263 17264### AutoLoad Sub 17265sub delete_overview { 17266 my $overview_top = $toplevel{"overview"}; 17267 if (defined $overview_top && Tk::Exists($overview_top)) { 17268 $overview_top->destroy; 17269 } 17270 eval q{ $radar_image->delete }; 17271 17272 delete $toplevel{"overview"}; 17273 # Done already in OnDestroy: $show_overview = 0; 17274} 17275 17276### AutoLoad Sub 17277sub overview_update { 17278 return if !$overview_canvas || !Tk::Exists($overview_canvas); 17279 my @a = $c->get_corners; 17280 my @c; 17281 my $i; 17282 my $ts = ($show_overview_mode eq 'region' 17283 ? \&transpose_small 17284 : \&transpose_medium); 17285 for($i = 0; $i < $#a; $i+=2) { 17286 push @c, $ts->(anti_transpose($a[$i], $a[$i+1])); 17287 } 17288 $overview_canvas->coords('zoomrect', @c[0,1, 0,3, 2,3, 2,1, 0,1]); 17289 my($midx, $midy) = (($c[2]-$c[0])/2+$c[0], 17290 ($c[3]-$c[1])/2+$c[1]); 17291 17292 if (!$overview_canvas->is_visible($midx, $midy)) { 17293 $overview_canvas->center_view($midx, $midy); 17294 } 17295} 17296 17297##### Suche ##################################################### 17298sub search_route { 17299 my($start, $ziel, $via_arr, $continue, %args) = @_; 17300 return if $in_search; 17301 $in_search++; 17302 my @via; @via = @$via_arr if defined $via_arr; 17303 17304 destroy_delayed_restack(); 17305 17306 IncBusy($top, %busy_watch_args); 17307 eval { 17308 status_message(""); 17309 my @res = do_search($start, $ziel, \@via, %args); 17310 17311 if (!@res) { 17312 die M"Keine Strecke gefunden.\n"; 17313 } 17314 17315 my @path = @{ $res[StrassenNetz::RES_PATH] }; 17316 if (!$continue) { 17317 clear_undecided_temp_blockings(); 17318 } 17319 check_path_in_blockings_net(\@path); 17320 my $old_nr; 17321 if ($continue) { 17322 save_route_to_register('cont'); # if $max_list > 0; 17323 $old_nr = $#coords; 17324 } else { 17325 # XXX shouldn't be necessary!!! 17326 my($save_start) = $search_route_points[0]; # XXX used to be [SRP_COORD]?! 17327 if (!exists $args{-undo} || $args{-undo}) { 17328 reset_undo_route(); 17329 } else { 17330 resetroute(); 17331 } 17332 push @search_route_points, $save_start; 17333 } 17334 17335 addpoints_xy(\@path); 17336 updatekm(); 17337 # continue with best route (but do not continue if the route was deleted before and @act_search_route is empty) 17338 if ($continue && @act_search_route) { 17339 push @act_search_route, 17340 $net->route_to_name([@path], -startindex => $old_nr); # XXX is wrong (?): +1); 17341 } else { 17342 # Use @realcoords instead of @path, in case it is continued, 17343 # but with an empty @act_search_route before 17344 @act_search_route = $net->route_to_name([@realcoords], -startindex=>0); 17345 } 17346 if (@path) { 17347 push @search_route_points, [join(",", @{ $path[-1] }), 17348 POINT_SEARCH]; 17349 } 17350 print "Route: ", join(", ", map { $_->[0] } @act_search_route), "\n" 17351 if $verbose; 17352 if (exists $args{-caller} && $args{-caller} eq 'chooseort') { 17353 zoom_view() if ($zoom_new_route_chooseort); 17354 } else { 17355 zoom_view() if ($zoom_new_route); 17356 } 17357 if ($auto_show_list) { 17358 $show_strlist = 1; 17359 show_route_strname(); 17360 } 17361 if ($edit_mode_flag) { 17362 require BBBikeAdvanced; 17363 path_to_selection(); 17364 } 17365 set_flag('via'); 17366 set_flag('ziel'); 17367 restack_delayed(); 17368 }; 17369 my $err = $@; 17370 $in_search = 0; 17371 DecBusy($top); 17372 status_message($err, 'err') if ($err); 17373} 17374 17375# Low-level search 17376sub do_search { 17377 my($start, $ziel, $via_ref) = @_; 17378 17379 # XXX $str_draw{'r'} ueberprfen, wenn im RB-Mode 17380 if (!$net and ($str_draw{'s'} || $str_draw{'l'})) { make_net() } 17381 print STDERR "Suche von <$start> bis <$ziel>" . (@$via_ref ? " via <@$via_ref>" : "") . "\n" 17382 if $verbose; 17383 my %extra_args; 17384 $extra_args{Via} = $via_ref; 17385 if (keys %ampeln) { 17386 if ($ampel_optimierung) { 17387 $extra_args{Ampeln} = 17388 {Net => \%ampeln, 17389 Penalty => $lost_strecke_per_ampel}; 17390 } elsif ($optprefs{'Ampeln'}) { 17391 $extra_args{Ampeln} = 17392 {Net => \%ampeln, 17393 Penalty => optprefs2penalty($optprefs{'Ampeln'})*100}; 17394 } # XXX 17395 if ($abbiege_optimierung) { 17396 $extra_args{Abbiegen} = {Penalty => $abbiege_penalty, 17397 Order => {'NN' => 0, 17398 'N' => 1, 17399 'NH' => 1, 17400 'H' => 2, 17401 'HH' => 3, 17402 'BAB' => 3, # XXX 17403 'B' => 4}}; 17404 } 17405 # XXX optprefs 17406 } 17407 17408 # Qualit�t, Handicap und tempor�re Handicaps 17409 foreach my $def ({OptSwitch => \$qualitaet_s_optimierung, 17410 OptName => 'Qualit�t', 17411 Speed => \%qualitaet_s_speed, 17412 MakeNet => \&make_qualitaet_net, 17413 CatPrefix => 'Q', 17414 ExtraArgsName => 'Qualitaet', 17415 }, 17416 {OptSwitch => \$handicap_s_optimierung, 17417 OptName => 'Sonstige Beeintr�chtigungen', 17418 Speed => \%handicap_s_speed, 17419 MakeNet => \&make_handicap_net, 17420 CatPrefix => 'q', 17421 ExtraArgsName => 'Handicap', 17422 }, 17423 ) { 17424 my $opt = $ {$def->{OptSwitch}}; 17425 my $optname = $def->{OptName}; 17426 if ($opt || (defined $optname && $optprefs{$optname})) { 17427 my $speed = $def->{Speed}; 17428 my $makenet = $def->{MakeNet}; 17429 my $catprefix = $def->{CatPrefix}; 17430 my $net = $makenet->(); 17431 my $penalty; 17432 if ($opt) { 17433 foreach (0 .. 4) { 17434 next if !defined $speed->{$catprefix . "$_"}; 17435 $penalty->{$catprefix . "$_"} = 17436 max_speed($speed->{$catprefix . "$_"}); 17437 } 17438 } else { 17439 foreach (0 .. 4) { 17440 next if !defined $penalty->{$catprefix . "$_"}; 17441 # XXX 17442 $penalty->{$catprefix . "$_"} = 17443 optprefs2penalty($optprefs{$def->{OptName}}) * $_; 17444 } 17445 } 17446 $extra_args{$def->{ExtraArgsName}} = 17447 {Net => $net, 17448 Penalty => $penalty, 17449 }; 17450 } 17451 } 17452 17453 if ($strcat_optimierung || $optprefs{'Kategorie'}) { 17454 # XXX wenn L zugeschaltet wird, mu� strcat_net aktualisiert werden 17455 if (!$strcat_net) { 17456 if ($multistrassen) { 17457 $strcat_net = new StrassenNetz $multistrassen; 17458 } elsif ($str_obj{'s'}) { 17459 $strcat_net = new StrassenNetz $str_obj{'s'}; 17460 } 17461 if ($strcat_net) { 17462 $strcat_net->make_net_cat; 17463 } 17464 } 17465 if ($strcat_net) { 17466 my $penalty; 17467 if ($strcat_optimierung) { 17468 foreach (keys %strcat_speed) { 17469 $penalty->{$_} = max_speed($strcat_speed{$_}); 17470 } 17471 } else { 17472# my %strcat_def = (B => HH => 100, 17473# H => 100, 17474# N => 100, 17475# NN => 100); 17476# foreach (keys %strcat_speed) { 17477# # XXX 17478# $penalty->{"Q$_"} = optprefs2penalty($optprefs{'Kategorie'})* $_; 17479# } 17480 } 17481 $extra_args{Strcat} = 17482 {Net => $strcat_net, 17483 Penalty => $penalty, 17484 }; 17485 } 17486 } 17487 if ($radwege_optimierung) { 17488 if (!$radwege_net) { 17489 my $radwege_exact = new Strassen "radwege_exact"; 17490 $radwege_net = new StrassenNetz $radwege_exact; 17491 $radwege_net->make_net_cat(-obeydir => 1); 17492 # add all other streets do not have cycle paths ... 17493 while (my($p1,$hash) = each %{ $net->{Net} }) { 17494 while (my($p2,$entf) = each %$hash) { 17495 if (!exists $radwege_net->{Net}{$p1}{$p2}) { 17496 $radwege_net->{Net}{$p1}{$p2} = "RW0"; 17497 $radwege_net->{Net}{$p2}{$p1} = "RW0"; 17498 } 17499 } 17500 } 17501 } 17502 my $penalty; 17503 foreach (keys %radwege_speed) { 17504 $penalty->{$_} = max_speed($radwege_speed{$_}); 17505 } 17506 17507 $extra_args{Radwege} = 17508 {Net => $radwege_net, 17509 Penalty => $penalty, 17510 }; 17511 } 17512 17513 if ($N_RW_optimization || $N_RW1_optimization) { 17514 # XXX check if $N_RW_net is up-to-date with respect to its 17515 # sources, or whether a new $N_RW_net should be build 17516 if (!$N_RW_net) { 17517 my $s = $multistrassen ? $multistrassen : $str_obj{'s'}; 17518 if (!$s) { 17519 warn "Can't get streets object, ignore N_RW optimization"; 17520 } else { 17521 $N_RW_net = new StrassenNetz $s; 17522 $N_RW_net->make_net_cyclepath(Strassen->new("radwege_exact"), 'N_RW'); 17523 } 17524 } 17525 if ($N_RW_net) { 17526 my $penalty = { "H" => 4, 17527 "H_Bus" => ($N_RW1_optimization ? 4 : 1), 17528 "H_RW" => 1, 17529 "N" => 1, 17530 "N_Bus" => 1, 17531 "N_RW" => 1 }; 17532 $extra_args{RadwegeStrcat} = 17533 {Net => $N_RW_net, 17534 Penalty => $penalty, 17535 }; 17536 } 17537 } 17538 17539 if ($tram_optimization) { 17540 if (!$tram_net) { 17541 $tram_net = StrassenNetz->new(Strassen->new('comments_tram')); # XXX -orig? 17542 $tram_net->make_net_cat; 17543 } 17544 if ($tram_net) { 17545 my $penalty = { "CS" => 4 }; # XXX about 20km/h -> 5km/h 17546 $extra_args{Tram} = 17547 {Net => $tram_net, 17548 Penalty => $penalty, 17549 }; 17550 } 17551 } 17552 17553 if ($green_optimization) { 17554 # XXX check if $green_net is up-to-date with respect to its 17555 # sources, or whether a new $green_net should be build 17556 if (!$green_net) { 17557 $green_net = new StrassenNetz(Strassen->new("green")); 17558 $green_net->make_net_cat; 17559 } 17560 my $penalty = ($green_optimization == 2 17561 ? { "green0" => 3, 17562 "green1" => 2, 17563 "green2" => 1, 17564 } 17565 : { "green0" => 2, 17566 "green1" => 1.5, 17567 "green2" => 1, 17568 } 17569 ); 17570 $extra_args{Green} = 17571 {Net => $green_net, 17572 Penalty => $penalty, 17573 }; 17574 } 17575 17576 if ($unlit_streets_optimization) { 17577 if (!$unlit_streets_net) { 17578 $unlit_streets_net = new StrassenNetz(Strassen->new("nolighting")); 17579 $unlit_streets_net->make_net_cat; 17580 } 17581 my $penalty = { "NL" => 4, 17582 }; 17583 $extra_args{UnlitStreets} = 17584 {Net => $unlit_streets_net, 17585 Penalty => $penalty, 17586 }; 17587 } 17588 17589 if ($steigung_optimierung) { 17590 if (!$steigung_net) { 17591 $steigung_net = new StrassenNetz Strassen->new; 17592 $steigung_net->make_net_steigung($net, \%hoehe); 17593 } 17594 my $penalty; 17595 my $act_power; 17596 if ($active_speed_power{Type} eq 'power') { 17597 $act_power = $power[$active_speed_power{Index}]; 17598 } else { 17599 $act_power = speed2power($speed[$active_speed_power{Index}]); 17600 } 17601 if (!defined $steigung_penalty_env{ActPower} || 17602 $steigung_penalty_env{ActPower} != $act_power) { 17603 $steigung_penalty = {}; 17604 } 17605 $steigung_penalty_env{ActPower} = $act_power; 17606 $extra_args{Steigung} = 17607 {Net => $steigung_net, 17608 Penalty => $steigung_penalty, 17609 PenaltySub => sub { steigung_penalty($_[0], $act_power) }, 17610 }; 17611 } 17612 if (!$sperre{'tragen'}) { 17613 $extra_args{Tragen} = 1; 17614 } 17615 $extra_args{Velocity} = get_active_speed()/3.6; # should be m/s 17616 # XXX Bislang noch keine M�glichkeit au�er /tmp/add.pl, um 17617 # $aufschlag zu setzen. 17618 # Der Alternativ-Strecken-Code braucht noch viel Arbeit. Als 17619 # erstes sollte ein Start/Ziel-Punkt, der zwischen zwei 17620 # Kreuzungen/Kurvenpunkten liegt, h�chstens einmal! durchfahren 17621 # werden. 17622 if ($aufschlag != 0 && $aufschlag != 1) { 17623 $extra_args{Aufschlag} = $aufschlag; 17624 $extra_args{All} = 1; 17625 } 17626 # XXX weitere m�gliche Optimierungen: 17627 # (benutzungspflichtige) Radwege 17628 # verkehrsberuhigte Zonen => 6 .. 20 km/h 17629 # Fu�g�ngerampeln: Abbremsen auf 10 km/h und gleich wieder hoch 17630 # Kreuzungen (Neben/Haupt, Haupt/Haupt ohne Ampel) 17631 # Berufsverkehr (Stau auf gro�en Stra�en => 15 .. 20 km/h) 17632 if ($search_stat) { 17633 $extra_args{Stat} = 1; 17634 } 17635 if ($search_visual) { 17636 $extra_args{'VisualSearch'} = {'Canvas' => $c, 17637 'Transpose' => \&transpose, 17638 'Delay' => 0.1, 17639 }; 17640 } 17641 if (%global_search_args) { 17642 while (my($k,$v) = each %global_search_args) { 17643 $extra_args{$k} = $v; 17644 } 17645 } 17646 if (keys %penalty_subs) { 17647 # Note: the %penalty_subs should only multiply $p, not add to 17648 # if there are more than one penalty sub! 17649 $extra_args{UserDefPenaltySub} = sub { 17650 my($p, $next_node, $last_node) = @_; 17651 while (my($k,$v) = each %penalty_subs) { 17652 $p = $v->($p, $next_node, $last_node); 17653 } 17654 $p; 17655 }; 17656 } 17657 17658 make_net() if (!$net); 17659 foreach my $ref (\$start, \$ziel) { 17660 if (!$net->reachable($$ref)) { 17661 add_new_point($net, $$ref); # XXX ja? 17662 } 17663 } 17664 my(@res) = $net->search($start, $ziel, %extra_args); 17665 17666 @res; 17667} 17668 17669# Wiederholung der Suche (evtl. mit neuen Parametern) 17670### AutoLoad Sub 17671sub re_search { 17672 my(%args) = @_; 17673 return if @search_route_points < 2; 17674 IncBusy($top, %busy_watch_args); 17675 eval { 17676 my(@old_search_route_points) = @search_route_points; 17677 @search_route_points = $old_search_route_points[SRP_COORD]; 17678 for(my $i=0; $i<$#old_search_route_points; $i++) { 17679 my $p1 = $old_search_route_points[$i]; 17680 my $p2 = $old_search_route_points[$i+1]; 17681 if ($p2->[SRP_TYPE] eq POINT_MANUELL) { 17682 addpoint_xy(split(/,/, $p2->[SRP_COORD])); 17683 push @search_route_points, [@$p2]; 17684 } else { 17685 search_route 17686 ($p1->[SRP_COORD], $p2->[SRP_COORD], 17687 undef, ($i == 0 ? '' : 'cont'), 17688 (exists $args{-undo} ? (-undo => $args{-undo}) : ()), 17689 ); 17690 } 17691 } 17692 }; 17693 my $err = $@; 17694 DecBusy($top); 17695 die $err if $err; 17696} 17697 17698sub re_search_gui { 17699 re_search(@_); 17700 update_route_strname(); 17701} 17702 17703sub add_via_to_current_search { 17704 my($before, $via, $after) = @_; 17705 17706 destroy_delayed_restack(); 17707 IncBusy($top, %busy_watch_args); 17708 eval { 17709 status_message(""); 17710 17711 my $insert_index; 17712 for my $i (0 .. $#search_route_points-1) { 17713 # We assume that the same before/after combination 17714 # exists exactly once in the route. This is a 17715 # rather pragmatic assumption. 17716 if ($search_route_points[$i]->[SRP_COORD] eq $before && 17717 $search_route_points[$i+1]->[SRP_COORD] eq $after) { 17718 $insert_index = $i; 17719 last; 17720 } 17721 } 17722 if (!defined $insert_index) { 17723 # Should never happen, no translation necessary: 17724 die "Cannot insert via point (no insertion index found using $before - $after)"; 17725 } 17726 17727 # Neither $before nor $after should be used multiple times. This 17728 # is still pragmatic, but less likely as the above assumption. 17729 my($before_index_in_route, $after_index_in_route); 17730 my $stage = 0; # 0: search for before, 1: search for after 17731 for my $i (0 .. $#realcoords) { 17732 if ($stage == 0) { 17733 if (join(",",@{$realcoords[$i]}) eq $before) { 17734 $before_index_in_route = $i; 17735 $stage = 1; 17736 } 17737 } else { 17738 if (join(",",@{$realcoords[$i]}) eq $after) { 17739 $after_index_in_route = $i; 17740 last; 17741 } 17742 } 17743 } 17744 if (!defined $before_index_in_route || 17745 !defined $after_index_in_route) { 17746 # Should never happen, no translation necessary: 17747 die "Cannot find either $before or $after in realcoords"; 17748 } 17749 17750 $via = add_new_point($net, $via); # may die if via is not insertable 17751 17752 my @res = do_search($before, $after, [$via]); 17753 if (!@res) { 17754 die M"Keine Strecke gefunden.\n"; 17755 } 17756 my @path = @{ $res[StrassenNetz::RES_PATH] }; 17757 check_path_in_blockings_net(\@path); 17758 17759 # XXX what about register/undo/... stuff? 17760 17761 splice @search_route_points, $insert_index+1, 0, [$via, POINT_SEARCH]; 17762 splice @realcoords, $before_index_in_route, ($after_index_in_route-$before_index_in_route)+1, @path; 17763 17764 # XXX Too much duplication with other route handling functions: 17765 # search_route, redraw_path, reverse_route ... 17766 my @oldrealcoords = @realcoords; 17767 my @oldsearchroutepoints = @search_route_points; # hack 17768 resetroute(); 17769 addpoints_xy(\@oldrealcoords); 17770 # XXX as a side effect, @realcoords and @coords are set to the new route 17771 @search_route_points = @oldsearchroutepoints; 17772 set_flag('via'); 17773 set_flag('ziel'); 17774 updatekm(); 17775 restack_delayed(); 17776 }; 17777 my $err = $@; 17778 DecBusy($top); 17779 status_message($err, 'err') if ($err); 17780} 17781 17782# Steigung mu� als Tausendfaches angegeben werden. 17783### AutoLoad Sub 17784sub steigung_penalty { 17785 my($steigung, $act_power) = @_; 17786 my $frac = ($steigung/1000+0.08)/(0.08*2); 17787 max_speed(power2speed($act_power, -grade => $steigung/1000)); 17788} 17789 17790### AutoLoad Sub 17791sub route_strname_on_map { 17792 my $xadd_anchor = $xadd_anchor_type->{'route'}; 17793 my $yadd_anchor = $yadd_anchor_type->{'route'}; 17794 17795 require Tk::StippleLine; 17796 17797 foreach my $def (@route_strnames) { 17798 my($str, $x, $y, $inx, $entf) = @$def; 17799 $str = $str .= " ($entf)" if defined $entf and $do_route_strnames_km; 17800 my(@tags) = ('route', 17801 "route-" . $inx, 17802 'routename'); 17803 TRY: { 17804 for my $check_against (['route', 'routename'], 17805 ['routename'], 17806 ) { 17807 my $returnanchor; 17808 if (draw_text_intelligent 17809 ($c, $x, $y, 17810 -text => $str, 17811 -tags => [@tags], 17812 -abk => $check_against, 17813 -checktagindex => 'all', 17814 -xadd => $xadd_anchor, 17815 -yadd => $yadd_anchor, 17816 -returnanchor => \$returnanchor, 17817 )) { 17818 Tk::StippleLine::create 17819 ($c, $x, $y, 17820 $x+$xadd_anchor->{$returnanchor}, 17821 $y+$yadd_anchor->{$returnanchor}, 17822 -fill => 'black', 17823 -width => 2, 17824 -tags => [@tags]); 17825 last TRY; 17826 } 17827 } 17828 $c->createText($x, $y, -text => $str, 17829 -anchor => 'w', 17830 -tags => [@tags]); 17831 } 17832 } 17833} 17834 17835### AutoLoad Sub 17836sub get_act_search_route { 17837 my @search_route; 17838 if (!@act_search_route) { 17839 if (@realcoords) { 17840 make_net() if !$net; 17841 @search_route = $net->route_to_name([@realcoords],-startindex=>0); 17842 } 17843 } else { 17844 @search_route = @act_search_route; 17845 } 17846 \@search_route; 17847} 17848 17849### AutoLoad Sub 17850sub show_route_strname { 17851 require Tk::HList; 17852 17853 my $t; 17854 my $withdraw_sub; 17855 if (defined $toplevel{strlist} && Tk::Exists($toplevel{strlist})) { 17856 if (!$show_strlist) { 17857 $toplevel{strlist}->withdraw; 17858 } else { 17859 my $was_withdrawn = $toplevel{strlist}->state ne "normal"; 17860 #XXX maybe combine with code below 17861 if ($was_withdrawn) { 17862 if (eval {require Tk::Placement; 1; }) { 17863 # XXX use placer also for other toplevels --- replace 17864 # all Popup(@popup_style) calls? 17865 warn "Use Tk::Placement, yet experimental..." if $devel_host; 17866 Tk::Placement::placer($toplevel{strlist}, -screen => $c, 17867 -addx => 20, -addy => 25, # XXX for fvwm 17868 ); 17869 } 17870 $toplevel{strlist}->deiconify; 17871 # raise nur ausf�hren, wenn es wirklich was zu sehen gibt 17872 #$toplevel{strlist}->raise; 17873 } 17874 17875 } 17876 } else { 17877 $toplevel{strlist} = $top->Toplevel(-title => M"Aktuelle Route", 17878 -class => "Bbbike Routeinfo"); 17879 set_as_toolwindow($toplevel{strlist}); 17880 $withdraw_sub = sub { $toplevel{strlist}->withdraw; 17881 $show_strlist = 0 }; 17882 $toplevel{strlist}->protocol('WM_DELETE_WINDOW', $withdraw_sub); 17883 $t = $toplevel{strlist}; 17884 } 17885 17886 undef @route_info; 17887 if (defined $t) { 17888 $t->SelectionOwn; 17889 # XXX maxbytes beachten 17890 $t->SelectionHandle(sub { 17891 my($offset, $maxbytes) = @_; 17892 my $res = route_info_to_text(); 17893 return undef if $offset > length($res); 17894 $res; 17895 }); 17896 } 17897 17898 my($bf, $f1); 17899 if (defined $t) { 17900 $bf = $t->Frame->pack(-fill => 'x', -side => "bottom"); 17901 $f1 = $t->Frame->pack(-fill => 'x', -side => "bottom"); 17902 $t->Label(-textvariable => \$ampelstatus_label_text, 17903 -anchor => 'w', 17904 -justify => "left")->pack(-fill => 'x', -side => 'bottom'); 17905 } 17906 17907 if (!Tk::Exists($route_strname_lbox)) { 17908 if (!defined $t) { 17909 die "No route_strname_lbox?!"; 17910 } 17911 $route_strname_lbox = $t->Scrolled 17912 ('HList', 17913 -header => 1, 17914 -columns => 5, 17915 -selectmode => 'extended', 17916 -scrollbars => 'osoe', 17917 -width => 68, # XXX 17918 )->pack(-expand => 1, -fill => 'both'); 17919 $route_strname_lbox->header('create', 0, -text => M"L�nge"); 17920 $route_strname_lbox->header('create', 1, -text => M"Gesamt"); 17921 $route_strname_lbox->header('create', 2, -text => M"Richtung"); 17922 $route_strname_lbox->header('create', 3, -text => M"Stra�e"); 17923 $route_strname_lbox->header('create', 4, -text => ""); 17924# $route_strname_lbox->header('create', 5, -text => M"Zeit"); 17925 } else { 17926 $route_strname_lbox->delete('all'); 17927 } 17928 17929 if ($do_route_strnames_comments && !$do_route_strnames_compact) { 17930 $route_strname_lbox->header('configure', 4, -text => M"Kommentar"); 17931 } else { 17932 $route_strname_lbox->header('configure', 4, -text => M""); 17933 } 17934 17935 undef $show_route_start; 17936 undef $show_route_ziel; 17937 undef @route_strnames; 17938 my(@search_route) = @{ get_act_search_route() }; 17939 17940 if (@search_route) { 17941 17942 if ($do_route_strnames_orte) { 17943 if (!$nearest_orte) { 17944 $nearest_orte = new_from_strassen Kreuzungen 17945 Strassen => _get_orte_obj(); 17946 $nearest_orte->make_grid; 17947 } 17948 } 17949 17950 if ($do_route_strnames_comments) { 17951 if (!$comments_net) { 17952 make_comments_net(); 17953 } 17954 } 17955 17956 $route_strname_lbox->configure 17957 (-command => sub { 17958 my $i = shift; 17959 if (defined $search_route[$i][4] and 17960 ref $search_route[$i][4] eq 'ARRAY') { 17961 my @line_coords; 17962 foreach my $nr ($search_route[$i][4][0]+1 .. 17963 $search_route[$i][4][1]+1) { 17964 my @coords = $c->coords("route-$nr"); 17965 push @line_coords, [ @coords ] if @coords; 17966 } 17967 mark_street(-coords => \@line_coords, 17968 -clever_center => 1, 17969 ) if @line_coords; 17970 } 17971 }); 17972 17973 # max angle meaning straight forward 17974 use constant ROUTE_STRAIGHT_ANGLE => 30; 17975 17976 if ($do_route_strnames_compact) { 17977 @search_route = $net->compact_route(\@search_route, 17978 -routestraightangle => ROUTE_STRAIGHT_ANGLE, 17979 ); 17980 } 17981 17982 my $ges_entf = 0; 17983 my($next_entf, $ges_entf_s, $next_winkel, $next_richtung, $next_extra) 17984 = ("", "", undef, ""); 17985 my $last_str; 17986 my %seen_comments; 17987 for(my $i = 0; $i <= $#search_route; $i++) { 17988 my($str, $index_arr); 17989 my($entf, $winkel, $richtung, $extra) 17990 = ($next_entf, $next_winkel, $next_richtung, $next_extra); 17991 my $entf_s; 17992 ($str, $next_entf, $next_winkel, $next_richtung, $index_arr, $next_extra) 17993 = @{$search_route[$i]}; 17994 my $route_strnames_index; 17995 if ($str ne '...' && 17996 (!defined $last_str || $last_str ne $str)) { 17997 $last_str = $str; 17998 $str = Strassen::strip_bezirk($str); 17999 if (!defined $show_route_start) { 18000 $show_route_start = $str; 18001 } 18002 $show_route_ziel = $str; 18003 if (ref $index_arr eq 'ARRAY' && 18004 defined $index_arr->[0] && 18005 defined $coords[$index_arr->[0]] && 18006 defined $coords[$index_arr->[0]+1]) { 18007 my($x, $y) = ($coords[$index_arr->[0]]->[0], 18008 $coords[$index_arr->[0]]->[1]); 18009 push @route_strnames, [$str, $x, $y, $index_arr->[0]]; 18010 $route_strnames_index = $#route_strnames; 18011 } 18012 } 18013 18014 if ($i > 0) { 18015 if (!$winkel) { $winkel = 0 } 18016 $winkel = int($winkel/10)*10; 18017 if ($winkel < ROUTE_STRAIGHT_ANGLE && (!$extra || !$extra->{ImportantAngle})) { 18018 $richtung = ""; 18019 } else { 18020 my $artikel = (!defined $Msg::lang || $Msg::lang =~ /^(|de)$/ 18021 ? Strasse::de_artikel($str) 18022 : "=>"); 18023 $richtung = 18024 ($winkel <= 45 ? M"halb" : '') . 18025 ($richtung eq 'l' ? M"links" : M"rechts") . " " . 18026 "($winkel�) " . $artikel; 18027 } 18028 18029 if ($do_route_strnames_orte) { 18030 my($nearest_ort_xy) = 18031 $nearest_orte->nearest_loop 18032 ($realcoords[$index_arr->[0]]->[0], 18033 $realcoords[$index_arr->[0]]->[1], 18034 IncludeDistance => 1); 18035 if ($nearest_ort_xy) { 18036 my $ort = $nearest_orte->get_first($nearest_ort_xy->[0]); 18037 # XXX evtl. Ort-Kat f�r 1000 beachten 18038 my $in_bei = ($nearest_ort_xy->[1] <= 1000 18039 ? M"in" : M"bei"); 18040 $richtung = "$in_bei " . 18041 (Strassen::split_ort($ort))[0] . 18042 ": $richtung"; 18043 } 18044 } 18045 18046 $ges_entf += $entf; 18047 $ges_entf_s = "(" . m2km($ges_entf) . ")"; 18048 $entf_s = M("nach")." ".m2km($entf, 3, 2); 18049 if (defined $route_strnames_index) { 18050 $route_strnames[$route_strnames_index]->[4] 18051 = m2km($ges_entf); 18052 } 18053 } elsif (@coords > 1) { 18054 my $compass = uc(BBBikeCalc::canvas_translation(BBBikeCalc::line_to_canvas_direction 18055 (@{ $coords[0] }, @{ $coords[1] }))); 18056 if (defined $Msg::lang && $Msg::lang !~ /^de/) { 18057 $compass =~ s/([NESW])/{N => M("nord"), 18058 E => M("ost"), 18059 S => M("s�d"), 18060 W => M("west")}->{$1}/gei; 18061 $richtung = $compass . M("w�rts"); 18062 } else { 18063 $richtung = M("nach")." ".$compass; 18064 } 18065 } 18066 18067 $route_strname_lbox->add($i, -text => $entf_s); 18068 $route_strname_lbox->itemCreate($i, 1, -text => $ges_entf_s); 18069 $route_strname_lbox->itemCreate($i, 2, -text => $richtung); 18070 $route_strname_lbox->itemCreate($i, 3, -text => $str); 18071 18072 my $etappe_comment = ""; 18073 if ($do_route_strnames_comments && $comments_net && 18074 !$do_route_strnames_compact) { 18075 my @comments; 18076 for my $i ($index_arr->[0] .. $index_arr->[1]) { 18077 my($etappe_comment_obj) = $comments_net->get_point_comment([@realcoords], $i, \%seen_comments, AsObj => 1); 18078 if (defined $etappe_comment_obj && 18079 # Ignore data from comments_kfzverkehr: 18080 $etappe_comment_obj->[Strassen::CAT()] !~ m{^[+-][12]$} 18081 ) { 18082 my $name = $etappe_comment_obj->[Strassen::NAME()]; 18083 $name =~ s{.*:\s+}{}; # strip street part 18084## The following is not needed if the comments are specific enough, i.e. 18085## "An der Ampel Voltairestr. die Gehwegseite wechseln" instead of 18086## "An der Ampel die Gehwegseite wechseln". As most comments are in this 18087## form already I will try to be consistent and have everything like 18088## this (of course, with osm data this would be another story, but 18089## currently CP/CP2/PI comments are not created by osm2bbd) 18090# # If the special comment is not at beginning 18091# # of an etappe, then it is useful to have the 18092# # exact crossing displayed. 18093# if ($i != $index_arr->[0] && $etappe_comment_obj->[Strassen::CAT()] =~ m{^(CP|CP2|PI)(;|$)?}) { 18094# my $crossings = all_crossings(); 18095# my $c = join ',', @{ $realcoords[$i] }; 18096# if ($crossings && exists $crossings->{$c}) { 18097# # XXX strip also "current" street 18098# my $cr_name = join '/', map { Strassen::strip_bezirk($_) } @{ $crossings->{$c} }; 18099# $name .= " (Kreuzung $cr_name)"; 18100# } 18101# } 18102 push @comments, $name; 18103 } 18104 } 18105 $etappe_comment = join("; ", @comments) if @comments; 18106 } 18107 $route_strname_lbox->itemCreate($i, 4, -text => $etappe_comment); 18108 push @route_info, [($entf_s||""), ($ges_entf_s||""), 18109 ($richtung||""), ($str || "")]; 18110 } 18111 $ges_entf_s = "(" . m2km($ges_entf+$next_entf) . ")"; 18112 my $i = $#search_route + 1; 18113 $route_strname_lbox->add($i, -text => M("nach")." ".m2km($next_entf, 3, 2)); 18114 $route_strname_lbox->itemCreate($i, 1, -text => "$ges_entf_s"); 18115 $route_strname_lbox->itemCreate($i, 2, -text => M"angekommen!"); 18116 push @route_info, [M("nach")." ".m2km($next_entf, 3, 2), 18117 $ges_entf_s, M"angekommen!", ""]; 18118 18119 my(@children) = $route_strname_lbox->info('children'); 18120 my $last_i = $children[-1]; 18121 for(my $j = $i+1; $j<=$last_i; $j++) { 18122 $route_strname_lbox->delete($j); 18123 } 18124 if ($do_route_strnames) { 18125 $c->delete("routename"); 18126 route_strname_on_map(\@route_strnames); 18127 } 18128 $toplevel{strlist}->raise; 18129 } else { 18130 $route_strname_lbox->add(0, -text => M"Keine Route"); 18131 } 18132 18133 return if !defined $t; 18134 18135 my $do_route_strnames_sub = sub { 18136 $c->delete("routename"); 18137 if ($do_route_strnames) { 18138 route_strname_on_map(\@route_strnames); 18139 } 18140 }; 18141 my $cb1 = $f1->Checkbutton(-text => M"Stra�ennamen an der Route", 18142 -variable => \$do_route_strnames, 18143 -font => $font{'small'}, 18144 )->pack(-side => 'left'); 18145 my $cb2 = $f1->Checkbutton(-text => M"km-Angaben", 18146 -variable => \$do_route_strnames_km, 18147 -command => $do_route_strnames_sub, 18148 -font => $font{'small'}, 18149 )->pack(-side => 'left'); 18150 my $cb2_enabler = sub { 18151 $cb2->configure(-state => $do_route_strnames ? "normal" : "disabled"); 18152 }; 18153 $cb2_enabler->(); 18154 $cb1->configure(-command => sub { 18155 $cb2_enabler->(); 18156 $do_route_strnames_sub->(); 18157 }); 18158 18159 $f1->Checkbutton(-text => M"Kompakt", 18160 -variable => \$do_route_strnames_compact, 18161 -command => sub { show_route_strname() }, 18162 -font => $font{'small'}, 18163 )->pack(-side => 'left'); 18164 if ($advanced) { # XXX funktioniert noch nicht so schoen intuitiv... 18165 $f1->Checkbutton(-text => M"Orte einbinden", 18166 -variable => \$do_route_strnames_orte, 18167 -command => sub { show_route_strname() }, 18168 -font => $font{'small'}, 18169 )->pack(-side => 'left'); 18170 } 18171 $f1->Checkbutton(-text => M"Kommentare", 18172 -variable => \$do_route_strnames_comments, 18173 -command => sub { show_route_strname() }, 18174 -font => $font{'small'}, 18175 )->pack(-side => 'left'); 18176 18177 my @bfb; 18178 my $endb = $bf->Button(Name => 'end', 18179 -command => $withdraw_sub, 18180 ); 18181 $t->bind('<Escape>' => sub { $endb->invoke }); 18182 push @bfb, $endb; 18183 push @bfb, $bf->Button 18184 (-text => M"Sichern (Text)", 18185 -command => sub { 18186 my($file) = $bf->getSaveFile 18187 (($os eq 'win' ? (-defaultextension => '.TXT') : ()), 18188 -title => M"Route sichern", 18189 -initialdir => $home, 18190 ); 18191 return if !defined $file; 18192 if ($os eq 'win' and $file !~ /\.txt$/i) { 18193 $file .= '.TXT'; 18194 } 18195 make_backup($file); 18196 if (open(ROUTE, ">$file")) { 18197 print ROUTE route_info_to_text(); 18198 close ROUTE; 18199 } else { 18200 status_message 18201 (Mfmt("Schreiben auf <%s> nicht m�glich: %s", $file, $!), 18202 'err'); 18203 } 18204 }, 18205 ); 18206 push @bfb, $bf->Button 18207 (-text => M"Sichern (GPX)", 18208 -command => sub { save_route_as_optimized_gpx() }, 18209 ); 18210 push @bfb, $bf->Button 18211 (-text => M("GPS (Garmin)"), 18212 -command => sub { send_route_to_gps() }, 18213 ); 18214 $t->bind('<Control-g>' => sub { send_route_to_gps() }); # XXX re-use toplevel binding? 18215 # If there is a txt => palm converter and a palm transfer program, 18216 # then show this button: 18217 require BBBikePalm; 18218 if (can_create_and_transfer_palm_docs()) { 18219 push @bfb, create_palm_button($bf); 18220 } 18221 my $print_text_sub = sub { 18222 my $font = shift; 18223 if (!$show_route_start) { $show_route_start = "???" } 18224 if (!$show_route_ziel) { $show_route_ziel = "???" } 18225 my $header = Mfmt("Route von %s bis %s", 18226 $show_route_start, $show_route_ziel); 18227 if ($^O eq 'MSWin32' && defined &Win32Util::start_txt_print) { 18228 # Make a nice filename as it's visible on the hardcopy: 18229 my $start = $show_route_start; 18230 my $ziel = $show_route_ziel; 18231 for ($start, $ziel) { 18232 s{[^A-Za-z0-9_-]}{_}g; 18233 } 18234 my $base = "Route_" . $start . "_" . $ziel; 18235 $base = substr($base, 0, 28) if length($base) > 28; 18236 $base .= ".txt"; 18237 18238 print_text_windows 18239 (-header => $header, 18240 -text => route_info_to_text(), 18241 -basename => $base, 18242 ); 18243 } else { # try pdflatex, then postscript, on Windows first Route::PDF 18244 my @try_order = qw(pdflatex postscript routepdf); 18245 if ($os eq 'win') { 18246 @try_order = qw(routepdf pdflatex postscript); 18247 } 18248 TRY: { 18249 for my $try (@try_order) { 18250 if ($try eq 'pdflatex') { 18251 last TRY if print_text_pdflatex(route_info_to_latex()); 18252 } elsif ($try eq 'postscript') { 18253 print_text_postscript 18254 (route_info_to_text(), 18255 -columns => 1, 18256 -header => $header, 18257 -font => $font, 18258 ); 18259 } elsif ($try eq 'routepdf') { 18260 print_route_pdf(); 18261 } 18262 } 18263 } 18264 } 18265 }; 18266 push @bfb, $bf->Button 18267 (-text => M"Drucken", 18268 -command => sub { $print_text_sub->($ps_fixed_font||"Courier7") }, 18269 ); 18270 if (_can_send_mail()) { 18271 push @bfb, $bf->Button 18272 (-text => M"Mail", 18273 -command => sub { 18274 if (@route_info) { 18275 $show_route_start = "???" unless $show_route_start; 18276 $show_route_ziel = "???" unless $show_route_ziel; 18277 enter_send_mail 18278 (Mfmt("BBBike-Route von %s bis %s", 18279 $show_route_start, $show_route_ziel), 18280 -data => route_info_to_text()); 18281 } 18282 }); 18283 } 18284 $t->bind('<Up>' => sub { $route_strname_lbox->yview(scroll => -1, 18285 'units') }); 18286 $t->bind("<Down>" => sub { $route_strname_lbox->yview(scroll => 1, 18287 'units') }); 18288 pack_buttonframe($bf, \@bfb); 18289 $endb->focus; 18290 #$t->Popup(@popup_style); 18291 18292 my $was_withdrawn = $t->state ne "normal"; 18293 if ($was_withdrawn) { 18294 if (eval {require Tk::Placement; 1; }) { 18295 # XXX use placer also for other toplevels --- replace 18296 # all Popup(@popup_style) calls? 18297 warn "Use Tk::Placement, yet experimental..."; 18298 Tk::Placement::placer($t, -screen => $c, 18299 -addx => 20, -addy => 25, # XXX for fvwm 18300 ); 18301 } else { 18302 $t->withdraw; 18303 my($x,$y) = ($top->rootx+$top->width-10, $top->rooty+$top->height-30); 18304 $t->idletasks; 18305 $x -= $t->reqwidth; 18306 $y -= $t->reqheight; 18307 $x = 0 if ($x < 0); 18308 $y = 0 if ($y < 0); 18309 $t->geometry("+$x+$y"); 18310 $t->deiconify; 18311 } 18312 } 18313} 18314 18315sub route_info_to_text { 18316 my $text = sprintf("%-14s %-10s %-26s %s\n", 18317 M"L�nge", M"Gesamt", M"Richtung", M"Stra�e"); 18318 $text .= "-" x 70 . "\n"; 18319 $text .= join "", map { sprintf("%-14s %-10s %-26s %s\n", @$_) } @route_info; 18320 $text; 18321} 18322 18323sub _get_route_title { 18324 my $route_name = "BBBike-Route"; 18325 if (defined $show_route_start and 18326 defined $show_route_ziel) { 18327 my $start = Strasse::short(Strassen::strip_bezirk($show_route_start), 3); # Start besser abk�rzen --- ist meist immer der Gleiche 18328 my $ziel = Strasse::short(Strassen::strip_bezirk($show_route_ziel), 2); 18329 $route_name = "BBBike: $start-$ziel"; 18330 } 18331 $route_name; 18332} 18333 18334sub route_info_to_html { 18335 my $html_route_name = _get_route_title(); 18336 eval { 18337 require HTML::Entities; 18338 HTML::Entities::encode_entities($html_route_name); 18339 }; 18340 warn $@ if $@; 18341 my $html = "<html><head><title>$html_route_name</title></head><body>"; 18342 $html .= join "", map { sprintf(" %s %s<br>\n%s <b>%s</b><br><br>\n", @$_) } @route_info; 18343 $html .= "</body></html>"; 18344 $html; 18345} 18346 18347# More tweaking could be done (other font face/size, real wide margins...) 18348sub route_info_to_latex { 18349 require BBBikeLaTeX; 18350 BBBikeLaTeX::route_info_to_latex(-routetitle => _get_route_title(), 18351 -routeinfo => \@route_info, 18352 ); 18353} 18354 18355sub update_route_strname { 18356 if (defined $toplevel{strlist} && Tk::Exists($toplevel{strlist})) { 18357 show_route_strname(); 18358 } 18359} 18360 18361sub add_custom_layers_to_net { 18362 my($net_source, $net_source_abk) = @_; 18363 while(my($abk,$val) = each %custom_net_str) { 18364 if ($val) { # XXX del? && $abk =~ /^L\d/) { 18365 eval { 18366 if (!$str_obj{$abk}) { 18367 my $s = Strassen->new($str_file{$abk}); 18368 if ($abk eq 'fz') { 18369 $s = $s->grepstreets(sub { $_->[Strassen::CAT] !~ m{(?:projected|inwork)} }); 18370 } 18371 $str_obj{$abk} = $s; 18372 } 18373 push @$net_source, $str_obj{$abk}; 18374 push @$net_source_abk, $abk; 18375 }; 18376 warn "Cannot get Strassen for $abk: $@" if $@; 18377 } 18378 } 18379} 18380 18381sub make_plz { 18382 require PLZ; 18383 my $plz; 18384 if (defined $city && $city eq 'Berlin') { 18385 require PLZ::Multi; 18386 my @objs = ("Berlin.coords.data", 18387 "Potsdam.coords.data", 18388 ); 18389 eval { 18390 # XXX why? 18391 my $plaetze = Strassen->new("plaetze"); 18392 push @objs, $plaetze if $plaetze; 18393 }; warn $@ if $@; 18394 18395 $plz = PLZ::Multi->new(@objs, -cache => 1); 18396 } else { 18397 $plz = PLZ->new; 18398 } 18399 $plz; 18400} 18401 18402sub make_net { 18403 my(%args) = @_; 18404 IncBusy($top); 18405 $progress->Init(-label => M("Berechnen des Stra�ennetzes")."...", 18406 -dependents => $c, 18407 -visible => 1, 18408 ); 18409 18410 my $user_dels; 18411 if ($net && $net->{_Deleted}) { # remember user dels 18412 require Data::Dumper; 18413 # clone: 18414 $user_dels = eval substr(Data::Dumper::Dumper($net->{_Deleted}), 7); 18415 } 18416 18417 undef $qualitaet_s_net; 18418 undef $handicap_s_net; 18419 undef $strcat_net; 18420 undef $radwege_net; 18421 undef $N_RW_net; 18422 undef $green_net; 18423 undef $unlit_streets_net; 18424 undef $steigung_net; 18425 undef $crossings; 18426 18427 eval { 18428 my $add_temp_blockings; 18429 my(@net_source, @net_source_abk); 18430 if ($net_type eq "r") { 18431 if (!$str_obj{'r'}) { 18432 $str_obj{'r'} = new Strassen $str_file{'r'}; 18433 } 18434 push @net_source, $str_obj{'r'}; 18435 push @net_source_abk, 'r'; 18436 } elsif ($net_type eq "us" || $net_type eq 'rus') { 18437 my @abk = ($net_type eq 'us' ? qw(u b) : qw(u b r)); 18438 foreach (@abk) { 18439 if (!$str_obj{$_}) { 18440 $str_obj{$_} = new Strassen $str_file{$_}; 18441 } 18442 push @net_source, $str_obj{$_}; 18443 push @net_source_abk, $_; 18444 } 18445 } elsif ($net_type eq 'wr') { 18446 if (!$str_obj{'wr'}) { 18447 $str_obj{'wr'} = Strassen->new($str_file{'wr'}); 18448 } 18449 push @net_source, $str_obj{'wr'}; 18450 push @net_source_abk, 'wr'; 18451 } elsif ($net_type eq 'custom') { 18452 add_custom_layers_to_net(\@net_source, \@net_source_abk); 18453 } else { 18454 if ($str_obj{'l'}) { 18455 push @net_source, $str_obj{'l'}; 18456 push @net_source_abk, 'l'; 18457 } 18458 if ($str_obj{'s'}) { 18459 my %s_restrict = %{$str_restrict{'s'}}; 18460 if ($net_type eq 's-car') { 18461 $str_obj{'sBAB'} = Strassen->new($str_file{'sBAB'}) 18462 if !$str_obj{'sBAB'}; 18463 push @net_source, $str_obj{'sBAB'}; 18464 push @net_source_abk, 'sBAB'; 18465 $s_restrict{'NN'} = 0; 18466 } 18467 my $is_restricted = 0; 18468#XXX use new_copy_restricted 18469 foreach (keys %s_restrict) { 18470 if ($s_restrict{$_} == 0 && 18471 $s_restrict{$_} ne 'P') { # Pl�tze 18472 $is_restricted = 1; 18473 last; 18474 } 18475 } 18476 if ($is_restricted) { 18477 my $restr_str = Strassen->new; 18478 # XXX Copy at least the map global directive 18479 if ($str_obj{'s'}->{GlobalDirectives}{map}) { 18480 @{ $restr_str->{GlobalDirectives}{map} } = @{ $str_obj{'s'}->{GlobalDirectives}{map} }; 18481 } 18482 $str_obj{'s'}->init; 18483 while(1) { 18484 my $ret = $str_obj{'s'}->next; 18485 last if !@{$ret->[Strassen::COORDS]}; 18486 my($cat) = $ret->[Strassen::CAT] =~ m{^([^:]+)}; # strip attributes 18487 next if !$s_restrict{$cat}; 18488 $restr_str->push($ret); 18489 } 18490 $restr_str->{File} = $str_obj{'s'}->file; 18491 $restr_str->{Id} = $str_obj{'s'}->id . "_restr_" . join("_", grep { $s_restrict{$_} } keys %s_restrict); 18492 push @net_source, $restr_str; 18493 push @net_source_abk, 's'; 18494 } else { 18495 if ($str_obj{'s'}) { 18496 push @net_source, $str_obj{'s'}; 18497 push @net_source_abk, 's'; 18498 } 18499 } 18500 } 18501 while(my($token, $bool) = each %add_net) { 18502 next if !$bool; 18503 if ($token eq 'custom') { 18504 add_custom_layers_to_net(\@net_source, \@net_source_abk); 18505 } else { 18506 $str_obj{$token} = Strassen->new($str_file{$token}) 18507 if !$str_obj{$token}; 18508 push @net_source, $str_obj{$token}; 18509 push @net_source_abk, $token; 18510 } 18511 } 18512 if (!@net_source) { # XXX n� 18513 my(@str_types) = ('s'); 18514 if ($args{'-l_add'}) { 18515 push @str_types, 'l'; 18516 } 18517 foreach my $str_type (@str_types) { 18518 cache_decider_init(); 18519 my $str = new Strassen $str_file{$str_type}; 18520 if (cache_decider() && $coord_system eq 'standard') { 18521 $str_obj{$str_type} = $str; 18522 } 18523 push @net_source, $str; 18524 push @net_source_abk, $str_type; 18525 } 18526 } 18527 18528 if ($show_active_temp_blockings && $current_temp_blockings_ms) { 18529 $add_temp_blockings = 1; 18530 } 18531 } 18532 18533 if (@net_source == 0) { 18534 die "Netz kann nicht berechnet werden, keine Sourcen"; 18535 } elsif (@net_source == 1) { 18536 $net = new StrassenNetz $net_source[0]; 18537 } else { 18538 $multistrassen = new MultiStrassen @net_source; 18539 $net = new StrassenNetz $multistrassen; 18540 } 18541 18542 $net->set_source(@net_source); 18543 $net->set_source_abk(@net_source_abk); 18544 18545 my $make_net_all = sub { 18546 if (defined $global_search_args{Algorithm} && 18547 $global_search_args{Algorithm} =~ /^C-A\*-2/) { 18548 $net->use_data_format($StrassenNetz::FMT_MMAP); 18549 } else { 18550 $net->use_data_format($StrassenNetz::FMT_HASH); 18551 } 18552 $net->make_net(Progress => $progress, 18553 UseCache => 0, 18554 ); 18555 18556 if ($net_type eq 's' || $net_type eq 's-car') { 18557 my @sperre_type; 18558 foreach ('einbahn', 'einbahn-strict', 'sperre', 'tragen', 'wegfuehrung') { 18559 push @sperre_type, $_ if $sperre{$_}; 18560 } 18561 if (@sperre_type) { 18562 eval { 18563 $net->make_sperre($sperre_file, 18564 Type => \@sperre_type, 18565 SpecialVehicle => get_special_vehicle(), 18566 ); 18567 }; warn $@ if $@; 18568 if ($net_type eq 's-car') { 18569 eval { 18570 $net->make_sperre("$datadir/gesperrt_car", 18571 Type => \@sperre_type, 18572 # no SpecialVehicle defined for vars 18573 ); 18574 }; warn $@ if $@; 18575 } 18576 } 18577 if ($sperre{'Q3'}) { 18578 eval { 18579 $net->make_sperre("qualitaet_s", Type => ['Q3']); 18580 if ($str_obj{'l'}) { 18581 $net->make_sperre("qualitaet_l", Type => ['Q3']); 18582 } 18583 }; warn $@ if $@; 18584 } 18585 if ($use_faehre) { 18586 $net->add_faehre($str_file{'e'}); 18587 } 18588 } elsif ($net_type eq 'us' || $net_type eq 'rus') { 18589 my @abk = ($net_type eq 'us' ? qw(u b) : qw(u b r)); 18590 18591 my $sperre_s = MultiStrassen->new(map { $p_file{"sperre_$_"} } @abk); 18592 $net->make_sperre($sperre_s, Type => "sperre"); 18593 18594 my @bhf_source; 18595 foreach (@abk) { 18596 if (!$p_obj{$_}) { 18597 $p_obj{$_} = new Strassen $p_file{$_}; 18598 } 18599 push @bhf_source, $p_obj{$_}; 18600 } 18601 my $bhf_obj = new MultiStrassen @bhf_source; 18602 $handicap_s_net = StrassenNetz->new(Strassen->new); 18603 my $h_net = $handicap_s_net->{Net} = {}; 18604 $net->add_umsteigebahnhoefe 18605 ($bhf_obj, -addmapfile => 'umsteigebhf', 18606 -cb => sub { 18607 my($self, $p1, $p2, $entf, $name) = @_; 18608 $h_net->{$p1}{$p2} = "q4"; # XXX just a hack to see some results... A best solution is to use the forthcoming penalty solution for the Marathon 18609 }); 18610 } elsif ($net_type eq 'wr') { 18611 # nothing special here... 18612 } 18613 }; 18614 18615 if ($use_mldbm) { 18616 eval { 18617 warn "Trying MLDBM cache...\n"; 18618 $net->load_net_mldbm; 18619 warn "OK!\n"; 18620 }; 18621 if ($@) { 18622 $make_net_all->(); 18623 eval { 18624 warn "Saving MLDBM cache...\n"; 18625 $net->save_net_mldbm; 18626 warn "OK!\n"; 18627 }; 18628 warn __LINE__ . ": $@" if $@; 18629 } 18630 } else { 18631 $make_net_all->(); 18632 } 18633 18634 if ($add_temp_blockings) { 18635 add_temp_blockings_to_net(); 18636 } 18637 18638 if ($verbose) { 18639 warn $net->statistics; 18640 } 18641 status_message(""); 18642 delete $pending{'recalc-net'}; 18643 }; 18644 status_message($@, 'err') if ($@); 18645 18646 if ($user_dels) { 18647 restore_user_dels($net, $user_dels); 18648 } 18649 18650 $progress->Finish; 18651 DecBusy($top); 18652} 18653 18654sub make_qualitaet_net { 18655 if (!$qualitaet_s_net) { 18656 # XXX hmmm, fails fataly if any of the layers is missing 18657 eval { 18658 $qualitaet_s_net = StrassenNetz->new 18659 (MultiStrassen->new(Strassen->new("qualitaet_s"), 18660 Strassen->new("qualitaet_l"))); 18661 $qualitaet_s_net->make_net_cat; 18662 }; 18663 if ($@ && !$no_original_datadir) { 18664 status_message($@, "info"); 18665 } 18666 } 18667 $qualitaet_s_net; 18668} 18669 18670sub make_handicap_net { 18671 if (!$handicap_s_net) { 18672 # XXX hmmm, fails fataly if any of the layers is missing 18673 eval { 18674 my @s = (Strassen->new("handicap_s"), 18675 Strassen->new("handicap_l"), 18676 ); 18677 $handicap_s_net = StrassenNetz->new(MultiStrassen->new(@s)); 18678 $handicap_s_net->make_net_cat; 18679 }; 18680 if ($@ && !$no_original_datadir) { 18681 status_message($@, "info"); 18682 } 18683 } 18684 $handicap_s_net; 18685} 18686 18687sub make_comments_net { 18688 if (!$str_obj{"comm"}) { 18689 $str_obj{'comm'} = _get_comments_obj(); 18690 } 18691 if ($str_obj{"comm"}) { 18692 $comments_net = new StrassenNetz $str_obj{"comm"}; 18693 $comments_net->make_net_cat(-net2name => 1, 18694 -multiple => 1, 18695 -obeydir => 1); 18696 } 18697} 18698 18699# Erzeugt einen Hash aller Kreuzungen 18700### AutoLoad Sub 18701sub all_crossings { 18702 if (!$crossings || !%$crossings) { 18703 my $s = $multistrassen ? $multistrassen : $str_obj{'s'}; 18704 return if !$s; 18705 $crossings = $s->all_crossings(RetType => 'hash', 18706 UseCache => 1); 18707 } 18708 $crossings; 18709} 18710 18711# User definable blockings 18712sub load_user_dels { 18713 my $file = shift || "$bbbike_configdir/userdels.bbd"; 18714 $net->load_user_deletions 18715 ($file, 18716 -oncallback => sub { set_usercross_image(@_) }, #XXX do not duplicate 18717 -offcallback => sub { # XXX do not duplicate 18718 my($xy1,$xy2) = @_; 18719 $c->delete("delnet-$xy1-$xy2"); 18720 $c->delete("delnet-$xy2-$xy1"); 18721 }, 18722 ); 18723 restore_cursor(); 18724} 18725 18726sub _save_umask (&) { 18727 my $code = shift; 18728 my $old_umask; 18729 eval { 18730 $old_umask = umask; 18731 }; 18732 eval { 18733 $code->(); 18734 }; 18735 my $err = $@; 18736 if (defined $old_umask) { 18737 umask $old_umask; 18738 } 18739 die $err if $err; 18740} 18741 18742sub save_user_dels { 18743 my $file = shift || "$bbbike_configdir/userdels.bbd"; 18744 my(%args) = @_; 18745 _save_umask { 18746 umask 022; 18747 $net->save_user_deletions($file, %args) if $net; 18748 }; 18749} 18750 18751sub restore_user_dels { 18752 my($net, $user_dels) = @_; 18753 # restore user deletions 18754 while(my($k1,$v1) = each %$user_dels) { 18755 while(my($k2,$v2) = each %$v1) { 18756 my $ok; 18757 if (exists $net->{Net}{$k1}{$k2}) { 18758 $net->{_Deleted}{$k1}{$k2} = $net->{Net}{$k1}{$k2}; 18759 $ok++; 18760 } 18761 if (exists $net->{_Deleted}{$k1}{$k2}) { 18762 $ok++; 18763 } 18764 if (exists $net->{Net}{$k2}{$k1}) { 18765 $net->{_Deleted}{$k2}{$k1} = $net->{Net}{$k2}{$k1}; 18766 $ok++; 18767 } 18768 if (exists $net->{_Deleted}{$k2}{$k1}) { 18769 $ok++; 18770 } 18771 if ($ok) { 18772 $net->del_net($k1, $k2, 2); 18773 # image still exists (well it should) 18774 } else { 18775 $c->delete("delnet-$k1-$k2"); 18776 $c->delete("delnet-$k2-$k1"); 18777 } 18778 } 18779 } 18780} 18781 18782# -force => 1: be quiet and do not ask or warn 18783sub delete_user_dels { 18784 my(%args) = @_; 18785 18786 my($any_delnet_tag) = $c->find("withtag", "delnet"); 18787 if (!defined $any_delnet_tag) { 18788 if (!$args{-force}) { 18789 $top->messageBox(-message => M"Keine benutzerdefinierten Sperrungen vorhanden."); 18790 } 18791 return; 18792 } 18793 18794 if ($args{-force} || 18795 $top->messageBox(-message => M"Alle benutzerdefinierten Sperrungen l�schen?", 18796 -type => "YesNo", 18797 -icon => "question") =~ /^yes/i) { 18798 $net->remove_all_from_deleted(sub { 18799 my($xy1,$xy2) = @_; 18800 $c->delete("delnet-$xy1-$xy2"); 18801 $c->delete("delnet-$xy2-$xy1"); 18802 }); 18803 restore_cursor(); 18804 } 18805} 18806 18807# Return "x,y" 18808sub set_coords_str { 18809 my($c, @tags) = @_; 18810 @tags = $c->gettags('current') if !@tags; 18811 return if !@tags; 18812 if ($tags[0] eq 'p' or $tags[0] eq 'pp' or $tags[0] =~ /^lsa/) { 18813 $tags[1]; 18814 } elsif ($tags[0] =~ /^[sSlL]$/ || 18815 $add_net{fz} && $tags[0] eq 'fz' || 18816 ($net_type eq 's-car' && $tags[0] eq 'sBAB') 18817 # XXX weitere Ausnahmen f�r $add_net{is} etc. definieren 18818 ) { 18819 my($pos, @points) = nearest_line_points_mouse($c, @tags); 18820 make_net() if !$net; 18821 if ($net->can("adjust_to_nearest")) { 18822 $points[0] = [ split /,/, 18823 $net->adjust_to_nearest(join ",", @{$points[0]}) 18824 ]; 18825 } else { 18826 $net->add_net($pos, @points); 18827 } 18828 my($x, $y) = @{$points[0]}; 18829 Route::_coord_as_string([$x,$y]); 18830 } else { 18831 my @accept_tags = qw(s l p pp lsa); 18832 if ($net_type eq 's-car') { push @accept_tags, 'sBAB' } 18833 my($item, @tags) = find_below($c, @accept_tags); 18834 return if !defined $item; 18835 set_coords($c, @tags); # hoffentlich keine Endlosrekursion... 18836 #die "Tag [@tags] ist weder p, pp, s noch l sollte nicht vorkommen!"; 18837 } 18838} 18839 18840### AutoLoad Sub 18841sub set_coords_rbahn { 18842 my($c, @tags) = @_; 18843 @tags = $c->gettags('current') if !@tags; 18844 return if !@tags; 18845 if ($tags[0] =~ /^r-[bf]g/) { 18846 $tags[1]; 18847 } else { 18848 my($item, @tags) = find_below($c, qw/r-bg r-fg/); 18849 return if !defined $item; 18850 set_coords($c, @tags); # hoffentlich keine Endlosrekursion... 18851 #die "Tag [@tags] ist weder p, pp, o, s noch l sollte nicht vorkommen!"; 18852 } 18853} 18854 18855### AutoLoad Sub 18856sub set_coords_usbahn { 18857 my($c, @tags) = @_; 18858 @tags = $c->gettags('current') if !@tags; 18859 return if !@tags; 18860 if ($tags[0] =~ /^[ub]-[bf]g/) { 18861 $tags[1]; 18862 } else { 18863 my($item, @tags) = find_below($c, qw/u-bg b-bg u-fg b-fg/); 18864 return if !defined $item; 18865 set_coords($c, @tags); # hoffentlich keine Endlosrekursion... 18866 #die "Tag [@tags] ist weder p, pp, o, s noch l sollte nicht vorkommen!"; 18867 } 18868} 18869 18870### AutoLoad Sub 18871sub set_coords_bahn { 18872 my($c, @tags) = @_; 18873 @tags = $c->gettags('current') if !@tags; 18874 return if !@tags; 18875 if ($tags[0] =~ /^[ubr]-[bf]g/) { 18876 $tags[1]; 18877 } else { 18878 my($item, @tags) = find_below($c, qw/u-bg b-bg u-fg b-fg r-bg r-fg/); 18879 return if !defined $item; 18880 set_coords($c, @tags); # hoffentlich keine Endlosrekursion... 18881 #die "Tag [@tags] ist weder p, pp, o, s noch l sollte nicht vorkommen!"; 18882 } 18883} 18884 18885### AutoLoad Sub 18886sub set_coords_wasserrouten { 18887 my($c, @tags) = @_; 18888 if ($tags[0] eq 'wr') { 18889 my($pos, @points) = nearest_line_points_mouse($c, @tags); 18890 make_net() if !$net; 18891 if ($net->can("adjust_to_nearest")) { 18892 $points[0] = [ split /,/, 18893 $net->adjust_to_nearest(join ",", @{$points[0]}) 18894 ]; 18895 } else { 18896 $net->add_net($pos, @points); 18897 } 18898 my($x, $y) = @{$points[0]}; 18899 Route::_coord_as_string([$x,$y]); 18900 } else { 18901 my($item, @tags) = find_below($c, qw/wr/); 18902 return if !defined $item; 18903 set_coords($c, @tags); # hoffentlich keine Endlosrekursion... 18904 #die "Tag [@tags] ist weder p, pp, s noch l sollte nicht vorkommen!"; 18905 } 18906} 18907 18908# Return "x,y" 18909### AutoLoad Sub 18910sub set_coords_custom { 18911 my($c, @tags) = @_; 18912 @tags = $c->gettags('current') if !@tags; 18913 return if !@tags; 18914 if ($tags[0] =~ /^L\d$/) { 18915 my($pos, @points) = nearest_line_points_mouse($c, @tags); 18916 make_net() if !$net; 18917 if ($net->can("adjust_to_nearest")) { 18918 $points[0] = [ split /,/, 18919 $net->adjust_to_nearest(join ",", @{$points[0]}) 18920 ]; 18921 } else { 18922 $net->add_net($pos, @points); 18923 } 18924 my($x, $y) = @{$points[0]}; 18925 Route::_coord_as_string([$x,$y]); 18926 } else { 18927 my($item, @tags) = find_below_rx($c, ['^L\d'], [0]); 18928 return if !defined $item; 18929 set_coords($c, @tags); # hoffentlich keine Endlosrekursion... 18930 } 18931} 18932 18933### AutoLoad Sub 18934sub user_edit_street { 18935 if (!$net) { 18936 make_net(); 18937 } 18938 status_message("Can't make net", "die") if !$net; 18939 my(@click_items) = ($net_type eq 's' || $net_type eq 's-car' 18940 ? qw(s l fz) 18941 : ($net_type =~ /^(r|us|rus)$/ 18942 ? map { $_ eq 's' ? 'b' : $_ } split //, $net_type 18943 : ($net_type eq 'wr' 18944 ? qw(wr) 18945 : warn "Unhandled net type $net_type" 18946 ) 18947 ) 18948 ); 18949 if (($net_type eq 's' || $net_type eq 's-car') && $use_faehre) { 18950 push @click_items, "e"; 18951 } 18952 if ($net_type eq 's-car') { 18953 push @click_items, 'sBAB'; # XXX check! 18954 } 18955 my($item, @tags) = find_below($c, @click_items); 18956 if (defined $item) { 18957 my($pos, @points) = nearest_line_points_mouse($c, @tags); 18958 my($xy1,$xy2) = (join(",",@{$points[1]}), join(",",@{$points[2]})); 18959 $net->toggle_deleted_line 18960 ($xy1,$xy2, 18961 sub { 18962 my($xy1,$xy2) = @_; 18963 set_usercross_image($xy1,$xy2) 18964 }, 18965 sub { 18966 my($xy1,$xy2) = @_; 18967 $c->delete("delnet-$xy1-$xy2"); 18968 $c->delete("delnet-$xy2-$xy1"); 18969 restore_cursor(); 18970 }); 18971 } 18972} 18973 18974### AutoLoad Sub 18975sub set_usercross_image { 18976 my($xy1,$xy2) = @_; 18977 if (!$usercross_photo) { 18978 $usercross_photo = 18979 load_photo($top, 'usercross'); 18980 } 18981 my($x1,$y1,$x2,$y2) = (split(/,/,$xy1), split(/,/,$xy2)); 18982 my($midx,$midy) = (int(($x2-$x1)/2+$x1), int(($y2-$y1)/2+$y1)); 18983 ($midx,$midy) = transpose($midx, $midy); 18984 $c->createImage($midx+2,$midy-1, 18985 -image => $usercross_photo, 18986 -tags => ["delnet", "delnet-$xy1-$xy2"]); 18987} 18988 18989### AutoLoad Sub 18990sub save_cursor { 18991 $c->{SavedCursor} = $c->get_cursor; 18992 if (!defined $c->{SavedCursor}) { 18993 $c->{SavedCursor} = "__DEFAULT__"; 18994 } 18995} 18996 18997### AutoLoad Sub 18998sub restore_cursor { 18999 if ($c->{SavedCursor}) { 19000 if ($c->{SavedCursor} eq '__DEFAULT__') { 19001 $c->set_cursor(undef); 19002 } else { 19003 $c->set_cursor($c->{SavedCursor}); 19004 } 19005 undef $c->{SavedCursor}; 19006 } 19007} 19008 19009sub set_cursor { 19010 my($type, $fallback) = @_; 19011 if (!defined $fallback && defined $type) { 19012 if ($type eq 'ziel') { 19013 $fallback = 'right_ptr'; 19014 } 19015 } 19016 if (!defined $type) { 19017 #$c->configure(-cursor => undef); 19018 $c->set_cursor(undef); 19019 status_message(''); 19020 } elsif (exists $cursor{$type}) { 19021 if (exists $cursor_mask{$type}) { 19022 #$c->configure(-cursor => 19023 $c->set_cursor(['@' . $cursor{$type}, 19024 $cursor_mask{$type}, 19025 'black', 'white']); 19026 } else { 19027 #$c->configure(-cursor => 19028 $c->set_cursor(['@' . $cursor{$type}, 'black']); 19029 } 19030 } elsif (defined $fallback) { 19031 $c->set_cursor($fallback); 19032 } else { 19033 #$c->configure(-cursor => undef); 19034 $c->set_cursor(undef); 19035 } 19036 if (defined $type && $type eq 'start') { 19037 status_message(M"Start ausw�hlen"); 19038 } elsif (defined $type && $type eq 'ziel') { 19039 status_message(M"Ziel ausw�hlen"); 19040 } 19041} 19042 19043### AutoLoad Sub 19044sub set_cursor_data { 19045 my($data, $persistent, $cur_data) = @_; 19046 my $tmpfile = "$tmpdir/cursor.$<-$$"; 19047 if ($persistent) { 19048 $tmpfile .= "_" . $persistent; 19049 } 19050 if ($os eq 'win') { 19051 if ($cur_data) { 19052 $tmpfile .= ".cur"; 19053 } else { 19054 $c->set_cursor(undef); 19055 return; 19056 } 19057 } else { 19058 $tmpfile .= ".xbm"; 19059 } 19060 if (open(C, ">$tmpfile")) { 19061 print C ($os eq 'win' ? $cur_data : $data); 19062 close C; 19063 #$c->configure(-cursor => ['@' . $tmpfile, 'black']); 19064 if ($os eq 'win') { 19065 $c->set_cursor(['@' . $tmpfile]); 19066 } else { 19067 $c->set_cursor(['@' . $tmpfile, 'black']); 19068 } 19069 if (!$persistent) { 19070 unlink $tmpfile; 19071 } else { 19072 $tmpfiles{$tmpfile}++; 19073 } 19074 } else { 19075 warn "Can't set cursor data with file $tmpfile: $!"; 19076 #$c->configure(-cursor => undef); 19077 $c->set_cursor(undef); 19078 } 19079} 19080 19081### AutoLoad Sub 19082sub set_route_start_street { 19083 my $street = shift; 19084 my $coord = choose_from_plz(-str => $street, 19085 -noshow => 0); 19086 set_route_start($coord) if $coord; 19087} 19088 19089### AutoLoad Sub 19090sub set_route_ziel_street { 19091 my $street = shift; 19092 my $coord = choose_from_plz(-str => $street, 19093 -noshow => 1); 19094 set_route_ziel($coord) if $coord; 19095} 19096 19097# Setzt den Start-Punkt der Route 19098# Eingabe ist "$x,$y" (realcoords) 19099# XXX viel Redundanz mit search_route_mouse! 19100### AutoLoad Sub 19101sub set_route_start { 19102 my $xy = shift; 19103 return if !defined $xy; 19104 my $search_route_start = $xy; 19105 19106 if (!$net) { make_net() } 19107 19108 if (!$net->reachable($search_route_start)) { 19109 my $new_search_route_start = $net->fix_coords($search_route_start); 19110 if (!$new_search_route_start) { 19111 $top->bell; 19112 status_message(M"Der Startort ist nicht erreichbar", 'warn'); 19113 undef $search_route_start; 19114 return; #goto CLEANUP; 19115 } else { 19116 $search_route_start = $new_search_route_start; 19117 } 19118 } 19119 19120 resetroute(); 19121 19122 # XXX vielleicht sollte man das unabh�ngige Setzen von Start/Ziel 19123 # erm�glichen (z.B. zuerst Ziel, dann Start ausw�hlen). Z.Zt. 19124 # mu� $search_route_ziel undefiniert werden. 19125 #XXXundef $search_route_ziel; 19126 $search_route_flag = 'ziel'; 19127 my($x, $y) = transpose(split(/,/, $search_route_start)); 19128 set_flag('start', $x, $y); 19129 set_cursor('ziel'); 19130 19131 @search_route_points = [$search_route_start, POINT_MANUELL]; 19132 19133 return; 19134} 19135 19136# Setzt den Ziel-Punkt der Route 19137# Eingabe ist "$x,$y" 19138# XXX viel Redundanz mit search_route_mouse_cont! 19139### AutoLoad Sub 19140sub set_route_ziel { 19141 my $xy = shift; 19142 my(%args) = @_; 19143 return if !defined $xy; 19144 19145#XXX dieser Teil ist halbnotwendig, falls der Startpunkt manuell 19146# gesetzt wurde und nearest_line_points aufgerufen werden muss. 19147# Allerdings funktioniert nearest_line_points anscheinend nicht ohne 19148# gemaltes Stra�ennetz, wohingegen die Telefonbuch-Stra�en-Auswahl 19149# ganz gut ohne gemaltes Stra�ennetz funktioniert. 19150# Deshalb vorerst disabled. 19151# 19152# if (@realcoords) { 19153# if ($net->reachable 19154# (Route::_coord_as_string($realcoords[$#realcoords]))) { 19155# $search_route_start 19156# = Route::_coord_as_string($realcoords[$#realcoords]); 19157# } 19158# my($tx, $ty) = transpose(@{$realcoords[$#realcoords]}); 19159# my($pos, @points) = nearest_line_points_xy($tx, $ty); 19160# if (@points) { # XXX wirklich? 19161# $net->add_net($pos, @points); 19162# $search_route_start = Route::_coord_as_string($points[0]); 19163# } else { 19164# addpoint_inter(); 19165# return; 19166# # $search_route_start = $search_route_ziel; 19167# } 19168# } 19169 19170# my $this_search_route_start = $search_route_ziel; 19171# if (!defined $this_search_route_start) { 19172# $this_search_route_start = $search_route_start; 19173# if (!defined $this_search_route_start) { 19174# return; 19175# } 19176# } 19177 19178 my $this_search_route_start = $search_route_points[-1]->[SRP_COORD]; 19179 return if (!defined $this_search_route_start); 19180 my $search_route_ziel = $xy; 19181 19182 if (!$net) { make_net() } 19183 19184 if (!$net->reachable($search_route_ziel)) { 19185 my $new_search_route_ziel = $net->fix_coords($search_route_ziel); 19186 if (!$new_search_route_ziel) { 19187 $top->bell; 19188 status_message(M"Der Zielort ist nicht erreichbar", 'warn'); 19189 undef $search_route_ziel; 19190 return; #goto CLEANUP; 19191 } else { 19192 $search_route_ziel = $new_search_route_ziel; 19193 } 19194 } 19195 # XXX nicht n�tig? my($x, $y) = transpose(split(/,/, $search_route_ziel)); 19196 search_route($this_search_route_start, $search_route_ziel, 19197 undef, 'cont', %args); 19198 update_route_strname(); 19199} 19200 19201sub search_route_mouse { 19202 my $by_button = shift; 19203 $map_mode = MM_SEARCH; 19204 if (!$search_route_flag) { 19205 $search_route_flag = 'start'; 19206 19207 if (!$lowmem) { 19208 if ($net_type eq 's' || $net_type eq 's-car') { 19209 if (!$net and ($str_draw{'s'} || $str_draw{'l'})) { 19210 make_net(); 19211 } 19212 } 19213 # XXX $str_draw{'r'} ueberprfen, wenn im RB-Mode 19214 $net->reset if ($net); 19215 } else { 19216 print STDERR M"`Stra�ennetz neu berechnen' vor Suche anklicken!\n"; 19217 } 19218 19219 set_cursor('start'); 19220 return; 19221 } elsif ($search_route_flag eq 'start') { 19222 if ($by_button) { 19223 undef $search_route_flag; 19224 goto CLEANUP; 19225 } 19226 my $search_route_start = set_coords($c); 19227 return if !defined $search_route_start; 19228 19229 make_net() if !$net; 19230 if (!$net->reachable($search_route_start)) { 19231 $top->bell; 19232 status_message(M"Der Startort ist nicht erreichbar", 'warn'); 19233 undef $search_route_start; 19234 return; #goto CLEANUP; 19235 } 19236 $search_route_flag = 'ziel'; 19237 my($x, $y) = transpose(split(/,/, $search_route_start)); 19238 set_flag('start', $x, $y); 19239 set_cursor('ziel'); 19240 @search_route_points = [$search_route_start, POINT_MANUELL]; 19241 return; 19242 } else { # ziel 19243 if ($by_button) { 19244 undef $search_route_flag; 19245 goto CLEANUP; 19246 } 19247 my $search_route_ziel = set_coords($c); 19248 return if !defined $search_route_ziel; 19249 if (!$net->reachable($search_route_ziel)) { 19250 $top->bell; 19251 status_message(M"Der Zielort ist nicht erreichbar", 'warn'); 19252 undef $search_route_ziel; 19253 return; #goto CLEANUP; 19254 } 19255 status_message(''); 19256 my $this_search_route_start = $search_route_points[-1]->[SRP_COORD]; 19257 return if !defined $this_search_route_start; 19258 search_route($this_search_route_start, $search_route_ziel); 19259 19260 # XXX duplicate code (see above) 19261 undef $search_route_flag; 19262 update_route_strname(); 19263 search_route_mouse_cont(); 19264 return; 19265 } 19266 19267 CLEANUP: 19268 undef $search_route_flag; 19269 set_cursor(undef); 19270} 19271 19272# Setzt das Suchen einer Route vom bisherigen Endpunkt fort. 19273# Der neue Zielpunkt wurde gerade per Maus angeklickt. 19274sub search_route_mouse_cont { 19275 if (!$search_route_flag) { 19276 # ??? Es existiert noch kein Startpunkt. 19277 $search_route_flag = 'ziel_cont'; 19278 set_cursor('ziel'); 19279 return; 19280 } else { 19281 my $this_search_route_start; 19282 if (!$net) { make_net() } # Netz wird neu berechnet 19283 if (@realcoords) { # Es existieren bereits Punkte in der Route. 19284 if ($net->reachable 19285 (Route::_coord_as_string($realcoords[-1]))) { 19286 # Der vorherige Zielpunkt ist direkt erreichbar (Punkt 19287 # existiert in der Datenbank) 19288 $this_search_route_start 19289 = Route::_coord_as_string($realcoords[-1]); 19290 } else { 19291 # Wann tritt dieser Fall auf? 19292 warn "In search_route_mouse_cont, 2nd case"; 19293 my($tx, $ty) = transpose(@{$realcoords[-1]}); 19294 my($pos, @points) = nearest_line_points_xy($tx, $ty); 19295 if (@points) { # XXX wirklich? 19296 $net->add_net($pos, @points); 19297 $this_search_route_start = Route::_coord_as_string($points[0]); 19298 @{$realcoords[-1]} = @{$points[0]}; # XXXX workaround 19299 # der aber nicht stimmt, wenn der letzte Punkt �ber 19300 # freehand eingegeben wurde ... 19301 # sigh, der ganze search_route_mouse_cont-Kram braucht eine 19302 # kr�ftige �berarbeitung ... :-( 19303 } else { 19304 addpoint_inter(); 19305 return; 19306 } 19307 } 19308 } 19309 my $search_route_ziel = set_coords($c); 19310 return if !defined $search_route_ziel; 19311 if (!$net->reachable($search_route_ziel)) { 19312 $top->bell; 19313 status_message(M"Der Zielort ist nicht erreichbar", 'warn'); 19314 #$search_route_ziel = $this_search_route_start; 19315 #undef $search_route_start; 19316 return; #goto CLEANUP; 19317 } 19318 status_message(''); 19319 search_route($this_search_route_start, $search_route_ziel, 19320 undef, 'cont'); 19321 19322 update_route_strname(); 19323 } 19324 CLEANUP: 19325} 19326 19327sub plugin_menu { 19328 my $opbm = shift; 19329 $opbm->command(-label => M"Plugin laden", 19330 -command => sub { 19331 my($file) = $top->getOpenFile 19332 (-title => M("Plugin laden"), 19333 -filetypes => [[M"Perl-Module" => '.pm'], 19334 [M"Alle Dateien" => '*']], 19335 -initialdir => "$FindBin::RealBin/plugins", 19336 ); 19337 if (defined $file) { 19338 load_plugin($file); 19339 } 19340 }); 19341 if (0) { # XXX The old Plugin lister could be removed completely some day 19342 $opbm->command(-label => M"Alle Plugins zeigen (alt)", 19343 -command => sub { 19344 require BBBikePlugin; 19345 BBBikePlugin::find_all_plugins($FindBin::RealBin, $top); 19346 }); 19347 } else { 19348 $opbm->command(-label => M"Alle Plugins zeigen", 19349 -command => sub { 19350 require BBBikePluginLister; 19351 BBBikePluginLister::plugin_lister($top, $FindBin::RealBin); 19352 }); 19353 } 19354} 19355 19356sub menu_entry_up_down { 19357 my($menu, $tag_group) = @_; 19358 my(@tags) = @$tag_group; 19359 $menu->separator; 19360 my $x; # dummy 19361 $menu->radiobutton(-label => M"oben zeichnen", 19362 -variable => \$x, 19363 -command => sub { 19364 foreach (@tags) { special_raise($_, 0) } 19365 restack(); 19366 }); 19367 $menu->radiobutton(-label => M"normal", 19368 -variable => \$x, 19369 -command => sub { 19370 foreach (@tags) { special_normal($_, 0) } 19371 restack(); 19372 }); 19373 $menu->radiobutton(-label => M"unten zeichnen", 19374 -variable => \$x, 19375 -command => sub { 19376 foreach (reverse @tags) { special_lower($_, 0) } 19377 restack(); 19378 }); 19379} 19380 19381sub menu_entry_choose_ort { 19382 my($menu, $abk, %args) = @_; 19383 if (exists $str_attrib{$abk}) { 19384 $menu->checkbutton(-label => $str_attrib{$abk}->[ATTRIB_PLURAL], 19385 -variable => \$str_draw{$abk}, 19386 -command => sub { plot('str',$abk); }, 19387 (defined $args{'-accelerator'} ? 19388 (-accelerator => $args{'-accelerator'}) : 19389 (), 19390 ), 19391 ); 19392 my %str_args; 19393 if (exists $args{'-strchooseortargs'}) { 19394 %str_args = %{$args{'-strchooseortargs'}}; 19395 } 19396 $menu->command(-label => Mfmt("%s ausw�hlen", $str_attrib{$abk}->[ATTRIB_SINGULAR]), 19397 -command => sub { choose_ort('s', $abk, %str_args) }); 19398 if ($args{'-strextrachoosemenuaction'}) { 19399 $args{'-strextrachoosemenuaction'}->(); 19400 } 19401 if (0) { # XXX Habe ich schon seit Jahren nicht genutzt! 19402 $menu->command 19403 (-label => Mfmt("Liste der %s neu erstellen", 19404 $str_attrib{$abk}->[ATTRIB_PLURAL]), 19405 -command => sub { choose_ort('s', $abk, -rebuild => 1, 19406 %str_args) }); 19407 $menu->command 19408 (-label => Mfmt("Update der %s", $str_attrib{$abk}->[ATTRIB_PLURAL]), 19409 -command => sub { undef $str_obj{$abk}; 19410 plot('str',$abk); 19411 }); 19412 $menu->command 19413 (-label => Mfmt("Schnelles Update der %s", 19414 $str_attrib{$abk}->[ATTRIB_PLURAL]), 19415 -command => sub { plot('str',$abk, FastUpdate => 1); }); 19416 } 19417 if ($advanced) { 19418 $menu->command 19419 (-label => "Lazy drawing", 19420 -command => sub { 19421 $str_draw{$abk} = 1 - $str_draw{$abk}; 19422 plot('str',$abk, -lazy => 1); 19423 }); 19424 } 19425 if ($args{'-strblockings'}) { 19426 my $sperre_abk = 'sperre_'.$abk; 19427 $menu->checkbutton 19428 (-label => M"gesperrte Strecken", 19429 -variable => \$p_draw{$sperre_abk}, 19430 -command => sub { 19431 plot_sperre($p_file{$sperre_abk}, 19432 -abk => $sperre_abk); 19433 }, 19434 ); 19435 } 19436 } 19437 19438 if (exists $p_attrib{$abk} && exists $str_attrib{$abk}) { 19439 $menu->separator; 19440 } 19441 19442 if (exists $p_attrib{$abk}) { 19443 $menu->checkbutton(-label => $p_attrib{$abk}->[ATTRIB_PLURAL], 19444 -variable => \$p_draw{$abk}, 19445 -command => sub { plot('p',$abk) }, 19446 (defined $args{'-accelerator_p'} ? 19447 (-accelerator => $args{'-accelerator_p'}) : 19448 (), 19449 ), 19450 ); 19451 my %p_args; 19452 if (exists $args{'-pchooseortargs'}) { 19453 %p_args = %{$args{'-pchooseortargs'}}; 19454 } 19455 $menu->command(-label => Mfmt("%s ausw�hlen", $p_attrib{$abk}->[ATTRIB_SINGULAR]), 19456 -command => sub { choose_ort('p', $abk, %p_args) }); 19457 if ($args{'-pextrachoosemenuaction'}) { 19458 $args{'-pextrachoosemenuaction'}->(); 19459 } 19460 if (0) { # XXX Habe ich schon seit Jahren nicht genutzt! 19461 $menu->command 19462 (-label => Mfmt("Liste der %s neu erstellen", $p_attrib{$abk}->[ATTRIB_PLURAL]), 19463 -command => sub { choose_ort('p', $abk, -rebuild => 1) }); 19464 $menu->command 19465 (-label => Mfmt("Update der %s", $p_attrib{$abk}->[ATTRIB_PLURAL]), 19466 -command => sub { undef $p_obj{$abk}; 19467 plot_point($abk); 19468 }); 19469 $menu->command 19470 (-label => Mfmt("Schnelles Update der %s", 19471 $p_attrib{$abk}->[ATTRIB_PLURAL]), 19472 -command => sub { plot('p',$abk, FastUpdate => 1); }); 19473 } 19474 if ($advanced) { 19475 $menu->command 19476 (-label => "Lazy drawing", 19477 -command => sub { 19478 $p_draw{$abk} = 1 - $p_draw{$abk}; 19479 plot('p',$abk, -lazy => 1); 19480 }); 19481 } 19482 } 19483} 19484 19485# bindet ein Men� an die rechte Taste 19486sub menuright { 19487 my($b, $menu) = @_; 19488 $b->bind('<ButtonPress-3>' => sub { 19489 if (0) { # old code XXX 19490 $menu->Popup(-popover => $b, 19491 -popanchor => 'n', 19492 -overanchor => 's', 19493 ); 19494 } else { 19495 my $e = $b->XEvent; 19496 my $X = $e->X; 19497 my $Y = $e->Y; 19498 $menu->Post($X,$Y); 19499 } 19500 } 19501 ); 19502} 19503 19504sub menuarrow { 19505 my($b, $menu, $col, %args) = @_; 19506 return if !menuarrow_unmanaged($b, $menu, %args); 19507 if (defined $col) { 19508 $b->grid(-row => $curr_row+1, -column => $col, -sticky => 'nesw'); 19509 } else { 19510 my(@packargs) = (exists $args{'-pack'} ? @{$args{'-pack'}} : ()); 19511 $b->pack(@packargs); 19512 } 19513} 19514 19515sub menuarrow_unmanaged { 19516 my($b, $menu, %args) = @_; 19517 return 0 if !$menuarrow_photo; 19518 $b->configure(-menu => $menu); 19519 $b->configure 19520 (-image => $menuarrow_photo, 19521 -takefocus => 1, 19522 -highlightthickness => 1, 19523 -indicatoron => 0, 19524 -bd => ($small_icons ? 0 : 2), 19525 -padx => 0, 19526 -pady => 0, 19527 ); 19528 19529 my $menulabel; 19530 if (defined $args{'-menulabel'}) { 19531 $menulabel = $args{'-menulabel'}; 19532 } else { 19533 for my $inx (0 .. $menu->index('last')) { 19534 if ($menu->type($inx) !~ /^(separator|tearoff)$/) { 19535 $menulabel = eval q{$menu->entrycget($inx, -label)}; 19536 last if defined $menulabel; 19537 } 19538 } 19539 } 19540 if (defined $menulabel and $menulabel ne '') { 19541 (my $balloonlabel = $menulabel) =~ s/~//; 19542 $balloon->attach($b, -msg => M("Men�")." $balloonlabel..."); 19543 # No balloon for actual menu: 19544 $balloon->attach($menu, -msg => []); 19545 } 19546 $menu->{BBBike_Menulabel} = $menulabel if !defined $menu->{BBBike_Menulabel}; 19547 $menu->{BBBike_Special} = $args{-special}; 19548 $b->bind('<ButtonPress-3>' => sub { $b->ButtonDown }); 19549 1; 19550} 19551 19552# error categories: 19553# info: never pops up a dialog: either writes to stderr or to the 19554# status bar if available 19555# infodlg: info with a dialog 19556# infoauto: info with auto-popped down toplevel 19557# warn: warn with a dialog 19558# err: error with a dialog 19559# die: error with a dialog and die afterwards 19560sub status_message { 19561 my($msg, $err) = @_; 19562 if (!defined $err || ($err =~ /^info/ && $err ne "infodlg" && $err ne "infoauto") || !$use_dialog) { 19563 if (!defined $progress) { 19564 if (defined $err && $err eq 'info-stack-trace') { 19565 require Carp; 19566 Carp::cluck($msg); 19567 } else { 19568 print STDERR "$msg\n"; 19569 } 19570 } else { 19571 $msg =~ s/\n+\z//; 19572 $status_label->configure(-text => $msg); 19573 if ($msg =~ /\n/) { 19574 set_status_button 19575 (-text => "OK", 19576 -command => sub { 19577 status_message("", "info"); 19578 }); 19579 } else { 19580 remove_status_button(); 19581 } 19582 } 19583 } elsif ($err eq 'infoauto') { 19584 my $l; 19585 if ($status_message_toplevel && Tk::Exists($status_message_toplevel)) { 19586 $status_message_toplevel->deiconify; 19587 $status_message_toplevel->raise; 19588 $l = $status_message_toplevel->Subwidget("Text"); 19589 } else { 19590 $status_message_toplevel = $top->Toplevel; 19591 set_as_toolwindow($status_message_toplevel); 19592 $status_message_toplevel->geometry('+30+30'); # XXX better geometry 19593 } 19594 if (!$l || !Tk::Exists($l)) { 19595 $l = $status_message_toplevel->Component("Label" => "Text", 19596 -background => Tk::NORMAL_BG, 19597 )->pack(qw(-fill both -expand 1)); 19598 } 19599 $l->configure(-text => $msg); 19600 } else { 19601 # warn or error 19602 if (!$top) { 19603 print STDERR "$msg\n"; 19604 } else { 19605 my %args = (-title => ($err eq 'warn' ? 'Warnung' : $err eq 'infodlg' ? 'Info' : 'Fehler'), 19606 -text => $msg, 19607 -bitmap => ($err eq 'warn' ? 'warning' : $err eq 'infodlg' ? 'info' : 'error'), 19608 -background => Tk::NORMAL_BG, 19609 -highlightbackground => Tk::NORMAL_BG, 19610 ); 19611 $splash_screen->Destroy if $splash_screen; undef $splash_screen; 19612 if ($status_message_dialog && Tk::Exists($status_message_dialog)) { 19613 ## Do not reconfigure existing dialog because of the 19614 ## (still!) two-seconds hang 19615 #$status_message_dialog->configure(%args); 19616 $status_message_dialog->destroy; 19617 } 19618 19619 my $Dialog = LongOrNormalDialog(); 19620 $status_message_dialog = $top->$Dialog(%args); 19621 # KDE's window manager seems to have a bug (?) 19622 # that the dialog might be behind other 19623 # transients. Fix the situation by forcing the dialog 19624 # on top. 19625 $kde->keep_on_top($status_message_dialog) if $kde; 19626 $status_message_dialog->Show; 19627 } 19628 } 19629 if (defined $err && $err eq 'die') { # also die 19630 require Carp; 19631 Carp::confess($msg); 19632 } 19633} 19634 19635sub info_auto_popdown { 19636 if ($status_message_toplevel && Tk::Exists($status_message_toplevel)) { 19637 $status_message_toplevel->withdraw; 19638 } 19639} 19640 19641sub LongOrNormalDialog { 19642 my $Dialog = "Dialog"; 19643 if (eval { require Tk::LongDialog; 1 }) { 19644 $Dialog = "LongDialog"; 19645 } else { 19646 require Tk::Dialog; 19647 } 19648 $Dialog; 19649} 19650 19651sub _blockings_infobar_exists { 19652 return if $blockings_infobar && Tk::Exists($blockings_infobar); 19653 my %stdcolor = (-bg => 'yellow'); 19654 $blockings_infobar = $c->Frame(Name => "blockingsinfobar", %stdcolor, -relief => 'raised', -borderwidth => 1); 19655 $blockings_infobar->Label(-text => M"M�gliche tempor�re Sperrungen auf der Route", %stdcolor)->pack(-side => "left"); 19656 $blockings_infobar->Button(-padx => 1, -pady => 1, -borderwidth => 1, 19657 -text => M"Anzeigen", 19658 -command => sub { show_blockings() }, 19659 )->pack(-side => "left", -padx => 10); 19660 $blockings_infobar->idletasks; # to force -reqheight to be set 19661} 19662 19663sub show_blockings_infobar { 19664 require Tk::SmoothShow; 19665 _blockings_infobar_exists(); 19666 Tk::SmoothShow::show($blockings_infobar); 19667} 19668 19669sub hide_blockings_infobar { 19670 if ($blockings_infobar && Tk::Exists($blockings_infobar)) { 19671 require Tk::SmoothShow; 19672 Tk::SmoothShow::hide($blockings_infobar); 19673 } 19674} 19675 19676sub set_status_button { 19677 my(%args) = @_; 19678 $status_button->grid(-column => $status_button_column, 19679 -row => 0); 19680 if (!$args{-command}) { 19681 die "-command missing"; 19682 } 19683 my $cmd = $args{-command}; 19684 $args{-command} = sub { 19685 $cmd->(); 19686 remove_status_button(); 19687 }; 19688 $status_button->configure(%args); 19689} 19690 19691sub remove_status_button { 19692 if ($status_button->manager) { 19693 $status_button->configure(-text => "", -command => \&Tk::NoOp); 19694 $status_button->gridForget; 19695 } 19696} 19697 19698sub add_new_point { 19699 my $net = shift; 19700 my $point = shift; 19701 my(%args) = @_; 19702 my($rx, $ry) = split(/,/, $point); 19703 my($tx, $ty) = transpose($rx, $ry); 19704 my($pos, @points) = nearest_line_points_xy($tx, $ty); 19705 # Korrektur des mittleren Punktes (-> index=0 !!!) 19706 $points[0] = [$rx, $ry]; 19707 if (@points) { 19708 $net->add_net($pos, @points); 19709 } 19710 unless ($args{'-quiet'}) { 19711 if (!$net->reachable($point)) { 19712 status_message(Mfmt("Der Punkt <%s> existiert im Netz nicht und kann auch nicht erzeugt werden", $point), "die"); 19713 } 19714 } 19715 join(",", @{ $points[0] }); 19716} 19717 19718sub nearest_line_points_xy { 19719 my($x, $y) = @_; 19720 my $start; 19721 my %seen; 19722 my $stage = 'closest'; 19723 my @find; 19724 my $find_i; 19725my $safe_loop = 0; #XXX 19726 while (1) { 19727die "too many loops, please report, line " . __LINE__ if ($safe_loop++ > 100); 19728 my $find; 19729 if ($stage eq 'closest') { 19730 ($find) = $c->find('closest', $x, $y, 0, $start); 19731 if (defined $find and $find ne '') { 19732 if (exists $seen{$find}) { 19733 $stage = 'overlapping'; 19734 next; 19735 } 19736 } 19737 } elsif ($stage eq 'overlapping') { 19738 if (!@find) { 19739 @find = $c->find('overlapping', $x-2, $y-2, $x+2, $y+2); 19740 $find_i = 0; 19741 } 19742 return undef if $find_i > $#find; 19743 $find = $find[$find_i]; 19744 $find_i++; 19745 } 19746 my(@tags) = $c->gettags($find); 19747 my $item_type_by_tag = $tags[0]; 19748 if (grep { $item_type_by_tag eq $_ } $net->get_source_abk) { 19749 return nearest_line_points($x, $y, @tags); 19750 } 19751 19752#XXX del: 19753# if ($net_type eq "r") { 19754# if ($tags[0] eq 'r') { 19755# return nearest_line_points($x, $y, @tags); # XXX 19756# } 19757# } elsif ($net_type eq "us") { 19758# if ($tags[0] =~ /^[ub]$/) { 19759# return nearest_line_points($x, $y, @tags); # XXX 19760# } 19761# } elsif ($net_type eq "rus") { 19762# if ($tags[0] =~ /^[ubr]$/) { 19763# return nearest_line_points($x, $y, @tags); # XXX 19764# } 19765# } elsif ($net_type eq 'wr') { 19766# if ($tags[0] eq 'wr') { 19767# return nearest_line_points($x, $y, @tags); # XXX 19768# } 19769# } elsif ($net_type eq 's-car') { 19770# if (($tags[0] =~ /^[sSlL]$/ || $tags[0] eq 'sBAB') && !grep { /^[sSlL]-label/ || /^sBAB-label/ } @tags) { 19771# return nearest_line_points($x, $y, @tags); # XXX 19772# } 19773# } else { 19774# if ($tags[0] =~ /^[sSlL]$/ && !grep { /^[sSlL]-label/ } @tags) { 19775# return nearest_line_points($x, $y, @tags); # XXX 19776# } 19777# } 19778 if ($stage eq 'closest') { 19779 $start = $find; 19780 $seen{$find}++; 19781 } 19782 } 19783} 19784 19785sub nearest_line_points_mouse { 19786 my($c, @tags) = @_; 19787 my $e = $c->XEvent; 19788 my($x, $y) = ($c->canvasx($e->x), $c->canvasy($e->y)); 19789 @tags = $c->gettags('current') if !@tags; 19790 @tags = grep { $_ ne 'current' } @tags; 19791 19792 my @forbidden_tags_rxs = ('^show$', '^route$', '-label'); # ignore labels and show marker etc. 19793 my $forbidden_tags_qr = join("|", @forbidden_tags_rxs); 19794 $forbidden_tags_qr = qr{$forbidden_tags_qr}; 19795 if (grep { $_ =~ $forbidden_tags_qr } @tags) { 19796 (undef, @tags) = find_below_rx($c, [q{.}], undef, \@forbidden_tags_rxs); 19797 } 19798 19799 my($pos, @points); 19800 eval { 19801 ($pos, @points) = nearest_line_points($x, $y, @tags); 19802 }; 19803 if ($@) { 19804 # 2nd try: restrict to just s and l types 19805 (undef, @tags) = find_below($c, 's', 'l'); 19806 ($pos, @points) = nearest_line_points($x, $y, @tags); 19807 } 19808 ($pos, @points); 19809} 19810 19811# Input arguments: 19812# x/y: current canvas coordinates 19813# tags: tags of the current canvas item 19814# Output: 19815# ($index, middlepoint(new), firstpoint, secondpoint) 19816# points are real coordinates 19817sub nearest_line_points { 19818 my($x, $y, @tags) = @_; 19819 my(@realcoords, @coords); 19820 if (defined $tags[3] && $tags[3] =~ /^(.+)-(\d+)$/) { 19821 my($type, $index) = ($1, $2); 19822 my $s; 19823 $s = $str_obj{$type}; 19824 if (!defined $s) { 19825 if (exists $str_file{$type}) { 19826 # XXX better: create a function type_to_filename 19827 my $filename = get_strassen_file($str_file{$type}); 19828 $str_obj{$type} = new Strassen $filename; 19829 $s = $str_obj{$type}; 19830 } 19831 if (!defined $s) { 19832 die "Streets not defined for type $type, Filename is $str_file{$type} XXX"; 19833 } 19834 } else { 19835 $s->reload; 19836 } 19837 my $ret = $s->get($index); 19838 if ($ret and @{$ret->[Strassen::COORDS]}) { 19839 # Erste Methode. $str_width wird von 2 bis 4 inkrementiert 19840 # (h�ngt von der Breite der Stra�en ab). 19841 for my $str_width (2 .. 4) { 19842 my $i; 19843 my($lastxx, $lastyy, $lastrx, $lastry); 19844 for($i = 0; $i <= $#{$ret->[Strassen::COORDS]}; $i++) { 19845 if ($ret->[Strassen::COORDS][$i] =~ /^(?:[A-Z])?(-?\d+(?:\.\d*)?),(-?\d+(?:\.\d*)?)$/) { 19846 my($rx, $ry) = ($1, $2); 19847 my($xx, $yy) = transpose($rx, $ry); 19848 push @realcoords, $rx, $ry; 19849 push @coords, transpose($xx, $yy); 19850 if (defined $lastxx && 19851 (($x >= $lastxx-$str_width && 19852 $x <= $xx+$str_width) || 19853 ($x >= $xx-$str_width && 19854 $x <= $lastxx+$str_width)) && 19855 (($y >= $lastyy-$str_width && 19856 $y <= $yy+$str_width) || 19857 ($y >= $yy-$str_width && 19858 $y <= $lastyy+$str_width))) { 19859 my($p1, $p2) = anti_transpose($x, $y); 19860 my($fp1, $fp2) = fusspunkt($lastrx, $lastry, 19861 $rx, $ry, 19862 $p1, $p2); 19863# XXX Achtung! $index kann nicht gebraucht werden, wenn 19864# mit Multistrassen gearbeitet wird. L�sung? 19865# Zuordnung von Strassen-Indices auf Multistrassen-Indices? 19866#XXX return ((defined $multistrassen ? undef : $index), 19867# XXX test it: 19868 my(@points) = ([int_round($fp1), int_round($fp2)], 19869 [$lastrx, $lastry], 19870 [$rx, $ry]); 19871 if ($net and 19872 $net->{Strassen}->isa('MultiStrassen')) { 19873 SEARCH: { 19874 for my $i (0 .. $#{$net->{SourceAbk}}) { 19875 if ($net->{SourceAbk}[$i] eq $type) { 19876 $index += 19877 $net->{Strassen}{FirstIndex}[$i]; 19878 last SEARCH; 19879 } 19880 } 19881 warn "Can't find index for MultiStrassen..."; 19882 undef $index; 19883 } 19884 } 19885 return ($index, @points); 19886 } else { 19887 ($lastxx, $lastyy) = ($xx, $yy); 19888 ($lastrx, $lastry) = ($rx, $ry); 19889 } 19890 } else { 19891 die "Can't parse coord: $ret->[Strassen::COORDS][$i]"; 19892 } 19893 } 19894 } 19895 } 19896 warn "nearest_line_points: failed 1st method 19897Tags are @tags 19898Type is $type 19899Index is $index 19900 19901Try 2nd method..."; 19902 } else { 19903 die "Can't find index from tags: @tags"; 19904 } 19905 # 2. Methode. Die n�chsten zwei Punkte in @coords werden einfach als 19906 # Nachbarn deklariert. Funktioniert ganz gut, es sei denn, die Stra�e 19907 # hat einen *sehr* kurvigen Verlauf (90�-Kurven etc.). 19908 my(@coords_dist, $nearest_i); 19909 my $i; 19910 if ($#coords > 0) { 19911 for($i = 0; $i < $#coords; $i+=2) { 19912 my($lx, $ly) = ($coords[$i], $coords[$i+1]); 19913 push(@coords_dist, 19914 Strassen::Util::strecke([$x, $y], 19915 [$coords[$i], $coords[$i+1]])); 19916 if (!defined $nearest_i or 19917 $coords_dist[$nearest_i] > $coords_dist[-1]) { 19918 $nearest_i = $#coords_dist; 19919 } 19920 } 19921 } 19922 my @res = ([anti_transpose($x, $y)]); 19923 if (!defined $nearest_i) { 19924 die "No nearest point???"; 19925 } elsif ($nearest_i == 0) { 19926 push(@res, [@realcoords[0..1]], [@realcoords[2..3]]); 19927 } elsif ($nearest_i == $#coords_dist) { 19928 my $last = $#coords_dist; 19929 push(@res, 19930 [@realcoords[$last*2-2 .. $last*2-1]], 19931 [@realcoords[$last*2 .. $last*2+1]]); 19932 } elsif ($coords_dist[$nearest_i-1] < $coords_dist[$nearest_i+1]) { 19933 push(@res, 19934 [@realcoords[$nearest_i*2-2 .. $nearest_i*2-1]], 19935 [@realcoords[$nearest_i*2 .. $nearest_i*2+1]]); 19936 } else { 19937 push(@res, 19938 [@realcoords[$nearest_i*2 .. $nearest_i*2+1]], 19939 [@realcoords[$nearest_i*2+2 .. $nearest_i*2+3]]); 19940 } 19941 (undef, @res); 19942} 19943 19944sub city_settings { 19945 $str_draw{'l'} = 0; 19946 $p_draw{'o'} = 0; 19947 $p_far_away{'o'} = 0; 19948 $str_far_away{'w'} = 0; 19949 $str_far_away{'l'} = 0; 19950 $str_regions{'l'} = []; 19951 $wasserumland = 0; 19952 pending(1, map { "replot-$_" } ("str-l", "p-o", "str-w", "str-l")); 19953} 19954 19955sub region_settings { 19956 $str_draw{'l'} = 1; # XXX set to str_draw{'s'}? 19957 $p_draw{'o'} = 1; 19958 $p_far_away{'o'} = 0; 19959 $str_far_away{'w'} = 0; 19960 $str_far_away{'l'} = 0; 19961 $str_regions{'l'} = []; 19962 $wasserumland = 1; 19963 pending(1, map { "replot-$_" } ("str-l", "p-o", "str-w", "str-l")); 19964} 19965 19966sub jwd_settings { 19967 $str_draw{'l'} = 1; # XXX set to str_draw{'s'}? 19968 $p_draw{'o'} = 1; 19969 $p_far_away{'o'} = 1; 19970 $str_far_away{'w'} = 1; 19971 $str_far_away{'l'} = 1; 19972 $str_regions{'l'} = []; # XXX Sachsen-Anhalt? 19973 $wasserumland = 1; 19974 pending(1, map { "replot-$_" } ("str-l", "p-o", "str-w", "str-l")); 19975} 19976 19977# Definiert, wie die grafischen Objekte "gestapelt" werden sollen. 19978# Also ganz unten Gew�sser und Fl�chen, dann Stra�en etc. und ganz oben 19979# Punkte wie Haltestellen, Orte und Kreuzungen. 19980# Allgemeine Fl�chen kommen unter Gew�sser, damit man z.B. bei in 19981# W�ldern gelegenen Seen nicht aufwendig ausschneiden muss. 19982# Ganz oben sind die mit "Custom draw" gezeichneten Strecken. 19983# Weitere Regeln: Labels von Orten sind unter anderen Ortspunkten (damit 19984# die Ortspunkte anw�hlbar bleiben), dagegen sind Labels von Bahnh�fen 19985# �ber den Bahnhofspunkten und Bahnstrecken (m�ssen nicht anw�hlbar sein). 19986# Development-Hilfen (fz) ganz oben anzeigen. 19987sub restack { 19988 my @real_order; 19989 @real_order = real_stack_order(); 19990 19991 foreach (@real_order) { 19992 $c->raise($_); 19993 } 19994 19995 Hooks::get_hooks("after_change_stacking")->execute(); 19996} 19997 19998# gibt das aktuelle Stacking aus 19999sub real_stack_order { 20000 my @real_order; 20001 20002 push @real_order, @special_lower; 20003 foreach (@normal_stack_order) { 20004 next if m{^\*.*\*$}; # ignore special tags 20005 if (!$special_lower{$_} && !$special_raise{$_}) { 20006 push @real_order, $_; 20007 } 20008 } 20009 push @real_order, @special_raise; 20010 @real_order; 20011} 20012 20013### AutoLoad Sub 20014sub real_type_stack_order { 20015 my @real_order = real_stack_order(); 20016 my @res; 20017 my %seen; 20018 foreach my $type (@real_order) { 20019 $type =~ s/^([^-]*)-.*/$1/; 20020 if (!$seen{$type}) { 20021 push @res, $type; 20022 $seen{$type}++; 20023 } 20024 } 20025 @res; 20026} 20027 20028### AutoLoad Sub 20029sub special_normal { 20030 my($abk, $delay) = @_; 20031 20032 if (exists $special_lower{$abk}) { 20033 delete $special_lower{$abk}; 20034 remove_from_array(\@special_lower, $abk); 20035 } 20036 20037 if (exists $special_raise{$abk}) { 20038 delete $special_raise{$abk}; 20039 remove_from_array(\@special_raise, $abk); 20040 } 20041 20042 restack() unless $delay; 20043} 20044 20045### AutoLoad Sub 20046sub special_raise { 20047 my($abk, $delay) = @_; 20048 20049 if (exists $special_lower{$abk}) { 20050 delete $special_lower{$abk}; 20051 remove_from_array(\@special_lower, $abk); 20052 } 20053 20054 $special_raise{$abk}++; 20055 remove_from_array(\@special_raise, $abk); 20056 push @special_raise, $abk; 20057 20058 restack() unless $delay; 20059} 20060 20061### AutoLoad Sub 20062sub special_lower { 20063 my($abk, $delay) = @_; 20064 20065 if (exists $special_raise{$abk}) { 20066 delete $special_raise{$abk}; 20067 remove_from_array(\@special_raise, $abk); 20068 } 20069 $special_lower{$abk}++; 20070 remove_from_array(\@special_lower, $abk); 20071 unshift @special_lower, $abk; 20072 20073 restack() unless $delay; 20074} 20075 20076sub remove_from_array { 20077 my($a_ref, $val) = @_; 20078 for(my $i = 0; $i <= $#{$a_ref}; $i++) { 20079 if ($a_ref->[$i] eq $val) { 20080 splice @$a_ref, $i, 1; 20081 $i--; 20082 } 20083 } 20084} 20085 20086sub destroy_delayed_restack { 20087 destroy_delayed_sub('restack'); 20088} 20089 20090sub fix_stack_order { 20091 my($abk) = @_; 20092 if (!grep { $_ eq $abk } @normal_stack_order) { 20093 push @normal_stack_order, $abk, "$abk-fg"; 20094 } 20095} 20096 20097### AutoLoad Sub 20098sub add_to_stack { 20099 my($abk, $how, $other_abk) = @_; 20100 return if (grep { $_ eq $abk } @normal_stack_order); 20101 if (defined $how) { 20102 if ($how eq 'lowermost') { 20103 unshift @normal_stack_order, $abk, "$abk-fg"; 20104 return; 20105 } elsif ($how eq 'topmost') { 20106 push @normal_stack_order, $abk, "$abk-fg"; 20107 return; 20108 } 20109 } 20110 20111 # Smart match do-it-yorself: 20112 my $other_abk_match = 20113 (ref $other_abk eq 'ARRAY' 20114 ? sub { 20115 my($tag) = @_; 20116 first { $_ eq $tag } @$other_abk; 20117 } 20118 : ref $other_abk eq 'Regexp' 20119 ? sub { 20120 my($tag) = @_; 20121 $tag =~ $other_abk; 20122 } 20123 : sub { 20124 my($tag) = @_; 20125 $tag eq $other_abk; 20126 } 20127 ); 20128 20129 my $i = 0; 20130 for my $tag (@normal_stack_order) { 20131 # XXX I think I don't have to check against '*...*' tags 20132 if ($other_abk_match->($tag)) { 20133 if ($how =~ m{^(after|above)$}) { 20134 splice @normal_stack_order, $i+1, 0, $abk, "$abk-fg"; 20135 return; 20136 } elsif ($how =~ m{^(before|below)$}) { 20137 splice @normal_stack_order, $i, 0, $abk, "$abk-fg"; 20138 return; 20139 } else { 20140 die "Cannot handle $how in add_to_stack"; 20141 } 20142 } 20143 $i++; 20144 } 20145 push @normal_stack_order, $abk, "$abk-fg"; 20146} 20147 20148### AutoLoad Sub 20149sub set_in_stack { 20150 my($abk, $how, $other_abk) = @_; 20151 remove_from_stack($abk); 20152 add_to_stack($abk, $how, $other_abk); 20153} 20154 20155### AutoLoad Sub 20156sub remove_from_stack { 20157 my($abk) = @_; 20158 my $abk_fg = "$abk-fg"; 20159 @normal_stack_order = grep { $_ ne $abk && $_ ne $abk_fg } @normal_stack_order; 20160} 20161 20162sub restack_delayed { 20163 # Use the delaying only on slow systems. For fast systems, 20164 # delaying is disturbing for the interactivity. 20165 delayed_sub(\&restack, -busy => $slowcpu ? !$edit_mode && !$edit_normal_mode : 0, 20166 -delay => $slowcpu ? 1000 : 300, 20167 -name => 'restack'); 20168} 20169 20170sub destroy_delayed_sub { 20171 my $name = shift; 20172 if ($delayed_sub_timer{$name}) { 20173 $delayed_sub_timer{$name}->cancel; 20174 delete $delayed_sub_timer{$name}; 20175 } 20176} 20177 20178sub delayed_sub { 20179 my($sub, %args) = @_; 20180 my $ms = $args{'-delay'} || 1000; 20181 my $name = $args{'-name'} || ""; 20182 my $busy = (defined $args{'-busy'} ? $args{'-busy'} : 1); 20183 destroy_delayed_sub($name); 20184 $delayed_sub_timer{$name} = $top->after 20185 ($ms, sub { 20186## DEBUG_BEGIN 20187#benchbegin("Delayed sub $name"); 20188## DEBUG_END 20189 IncBusy($top) if $busy; 20190 eval { 20191 $sub->(); 20192 }; 20193 warn __LINE__ . ": $@" if $@; 20194 DecBusy($top) if $busy; 20195## DEBUG_BEGIN 20196#benchend(); 20197## DEBUG_END 20198 }); 20199} 20200 20201### AutoLoad Sub 20202sub show_logo { # und About 20203 my $as_about = shift || ''; 20204 return unless $use_logo || $as_about; 20205 20206 my $logotop = redisplay_top($top, "about-$as_about", 20207 -title => ($as_about ? M('�ber').' ' : '') 20208 . 'BBBike', 20209 -background => 'white'); 20210 return if !defined $logotop; 20211 20212 my %git_info; 20213 if ($as_about && -r "$FindBin::RealBin/miscsrc/BBBikeGit.pm") { 20214 require "$FindBin::RealBin/miscsrc/BBBikeGit.pm"; 20215 %git_info = BBBikeGit::git_info(); 20216 } 20217 20218 $logotop->optionAdd("*" . substr($logotop->PathName, 1) 20219 . "*background" => 'white', 'startupFile'); 20220 $logotop->optionAdd("*" . substr($logotop->PathName, 1) 20221 . "*foreground" => 'blue3', 'startupFile'); 20222 $logotop->transient($top) unless $as_about; 20223 my $ff = $logotop->Frame(-relief => ($as_about ? 'ridge' : 'flat'), 20224 -bd => ($as_about ? 2 : 0), 20225 )->pack(-fill => 'both', -expand => 1); 20226 my $f = $ff->Frame->pack(-side => 'left', 20227 -fill => 'both', -expand => 1, 20228 -padx => 4, -pady => 4, 20229 ); 20230 my %common_args = 20231 ( 20232 -padx => 5, 20233 -highlightthickness => 1, 20234 -highlightbackground => 'white', 20235 -relief => 'flat', 20236 -borderwidth => 0, 20237 ); 20238 my $Button_or_Label = ($as_about ? "Button" : "Label"); 20239 my $www_b = 20240 $f->$Button_or_Label 20241 (-text => 20242 "$progname $VERSION\n" . 20243 ($git_info{patchnum} ? "(patchnum $git_info{patchnum})\n" : '') . 20244 M("Ein Informationssystem f�r Radfahrer in Berlin") . 20245 "\n\n� 1995-2012 Slaven Rezic", 20246 %common_args, 20247 -wraplength => 320, 20248 -font => $font{'bold'}, 20249 -pady => 0, 20250 ($as_about ? 20251 (-command => sub { 20252 require WWWBrowser; 20253 WWWBrowser::start_browser($BBBike::BBBIKE_WWW); 20254 }, 20255 ) : ()) 20256 )->pack(-fill => 'x'); 20257 $balloon->attach($www_b, -msg => M"WWW-Version aufrufen") 20258 if $balloon; 20259 my $copying_b = 20260 $f->$Button_or_Label 20261 (-text => M"Siehe auch die Datei COPYING", 20262 %common_args, 20263 ($as_about ? 20264 (-command => sub { copying_viewer($logotop) }) : ()), 20265 )->pack(-fill => "x"); 20266 if (%git_info) { 20267 $f->$Button_or_Label 20268 (-text => M"Detaillierte GIT-Information", 20269 %common_args, 20270 ($as_about ? 20271 (-command => sub { 20272 require Data::Dumper; 20273 my $t = $logotop->Toplevel(-title => M"Detaillierte GIT-Information"); 20274 my $txt = $t->Scrolled("ROText", -scrollbars => "osoe")->pack(-fill => "both", -expand => 1); 20275 local $Data::Dumper::Sortkeys = $Data::Dumper::Sortkeys = 1; # doubled to cease -w 20276 local $Data::Dumper::Indent = 2; 20277 my $dump = Data::Dumper::Dumper(\%git_info); 20278 $dump =~ s{^(.*?=)}{" " x length $1}e; 20279 $txt->insert('end', $dump); 20280 $t->Button(Name => 'close', 20281 -command => sub { $t->destroy }, 20282 )->pack(-fill => "x", -expand => 1); 20283 }) : ()), 20284 )->pack(-fill => 'x'); 20285 } 20286 if ($as_about) { 20287 my $os_info = "OS: $^O"; 20288 if ($os eq 'win') { 20289 $os_info .= " (" . ($Config{'cc'} =~ /^gcc/ 20290 ? 'gcc' : 20291 ($Config{'cc'} eq 'cl.exe' 20292 ? 'Visual C' 20293 : $Config{'cc'})) . ")"; 20294 } 20295 # Are we running an emulation? 20296 # This could be wrong, e.g. if cygwin's uname is 20297 # in the PATH, but Win32 perl is running, 20298 # hence the "maybe" 20299 if (is_in_path("uname")) { 20300 chomp(my $real_os = `uname`); 20301 if ($^O !~ /^$real_os$/i) { 20302 $os_info .= " (Real OS, maybe: $real_os)"; 20303 } 20304 } 20305 $f->Label(-text => "perl $]\nTk $Tk::VERSION\n$os_info", 20306 -font => $font{'small'}, 20307 -justify => 'left', 20308 )->pack(-anchor => 'w', -expand => 1, 20309 -fill => 'x'); 20310 } 20311 20312 # Send mail to software maintainer 20313 my $mail_b = 20314 $f->$Button_or_Label 20315 (-text => $BBBike::EMAIL, 20316 -pady => 0, 20317 %common_args, 20318 ($as_about ? 20319 (-command => sub { 20320 if ($^O eq 'MSWin32') { 20321 require Win32Util; 20322 Win32Util::start_mail_composer($BBBike::EMAIL); 20323 } else { 20324 enter_send_mail(M"BBBike perl/Tk", 20325 -to => $BBBike::EMAIL, 20326 ); 20327 } 20328 }) : ()), 20329 -font => $font{'normal'})->pack(-fill => 'x'); 20330 $balloon->attach($mail_b, -msg => M"Mail an den Autor schicken") 20331 if $balloon; 20332 20333 $ff->Label(-image => $srtbike_photo 20334 )->pack(-side => 'left', -anchor => "ne"); 20335 if ($as_about) { 20336 my $okb = $logotop->Button(Name => 'ok', 20337 -command => sub { hide_logo($as_about) }, 20338 )->pack(-anchor => 'c', -pady => 4); 20339 $okb->focus; 20340 $logotop->bind('<Return>' => sub { $okb->invoke }); 20341 } else { 20342 $logotop->transient($top); 20343 } 20344 $logotop->withdraw; 20345 $logotop->Popup(-popover => ($as_about ? 'cursor' : $top)); 20346 $logotop->update; # damit der Inhalt sofort erscheint 20347} 20348 20349### AutoLoad Sub 20350sub hide_logo { 20351 my $as_about = shift || ''; 20352 my $t = $toplevel{"about-$as_about"}; 20353 if (defined $t && Tk::Exists($t)) { 20354 $t->destroy; 20355 undef $toplevel{"about-$as_about"}; 20356 } 20357} 20358 20359### AutoLoad Sub 20360sub copying_viewer { 20361 my $top = shift; 20362 simple_file_viewer($top, "$FindBin::RealBin/COPYING", 20363 -title => M"COPYING", 20364 -class => "Bbbike Copyright", 20365 ); 20366} 20367 20368### AutoLoad Sub 20369sub simple_file_viewer { 20370 my($top, $file, %args) = @_; 20371 my $title = $args{-title}; 20372 my $class = $args{-class}; 20373 if (open(C, $file)) { 20374 binmode C; 20375 my $t = $top->Toplevel 20376 ((defined $title ? (-title => $title) : ()), 20377 (defined $class ? (-class => $class) : ()), 20378 ); 20379 my $txt = $t->Scrolled("ROText", -scrollbars => "osoe")->pack(-fill => "both", -expand => 1); 20380 while(<C>) { 20381 $txt->insert("end", $_); 20382 } 20383 close C; 20384 $t->Button(Name => 'close', 20385 -command => sub { $t->destroy }, 20386 )->pack(-fill => "x", -expand => 1); 20387 } else { 20388 status_message(Mfmt("Die Datei %s kann nicht ge�ffnet werden: %s", 20389 $file, $!), "error"); 20390 } 20391} 20392 20393###################################################################### 20394# Utilities ... 20395 20396### AutoLoad Sub 20397sub usage { 20398 my($msg, $getopt_listref) = @_; 20399 my(@getopt_list) = @$getopt_listref; 20400 if (defined $msg) { 20401 $msg .= "\n"; 20402 } else { 20403 $msg = ''; 20404 } 20405 20406 my @opt; 20407 my $i; 20408 for($i = 0; $i <= $#getopt_list; $i+=2) { 20409 if ($getopt_list[$i] =~ /([^!=]+)(!|=.)?$/) { 20410 my $mod = $2 || ''; 20411 if ($mod eq '!') { 20412 push @opt, map { "[-[no]$_]" } split(/\|/, $1); 20413 } else { 20414 push @opt, map { "[-$_$mod]" } split(/\|/, $1); 20415 } 20416 } else { 20417 push @opt, "[-$getopt_list[$i]]"; 20418 } 20419 } 20420 die $msg . wrap("usage: $progname ", "\t", join(" ", @opt)) 20421 . "\n"; 20422} 20423 20424### AutoLoad Sub 20425sub windrose { # funktioniert nur mit quadratischen Buttons 20426 my($senkrecht) = @_; # "Geschwindigkeit" des Scrollens 20427 my $e = $windrose_button->XEvent; 20428 my($x, $y) = ($e->x, $e->y); 20429 my($w, $h) = ($windrose_button->width, $windrose_button->height); 20430 $senkrecht = 1 unless defined $senkrecht; 20431 20432 my $is_center = sub { 20433 my($x, $y) = @_; 20434 ($x > $w*0.4 && $x < $w*0.6 && 20435 $y > $h*0.4 && $y < $h*0.6) 20436 }; 20437 my $center_delay; 20438 20439 if ($is_center->($x, $y) && !$center_delay) { 20440 $center_delay = $c->after 20441 (1000, sub { 20442 undef $center_delay; 20443 my $e = $windrose_button->XEvent; 20444 my($x, $y) = ($e->x, $e->y); 20445 if ($is_center->($x, $y)) { 20446 $c->center_view; 20447 } 20448 }); 20449 } elsif ($x-0.25*$w < 0.5*$y) { 20450 if ($x-0.75*$w > -0.5*$y) { 20451 my($y) = $c->yview; 20452 $c->yview(scroll => $senkrecht, 'units'); # S 20453 } elsif ($x+0.5*$w > 2*$y) { 20454 $c->yview(scroll => -$senkrecht, 'units'); # N 20455 $c->xview(scroll => -$senkrecht, 'units'); # W 20456 } elsif ($x-1.5*$w > -2*$y) { 20457 $c->yview(scroll => $senkrecht, 'units'); # S 20458 $c->xview(scroll => -$senkrecht, 'units'); # W 20459 } else { 20460 $c->xview(scroll => -$senkrecht, 'units'); # W 20461 } 20462 } else { 20463 if ($x-0.75*$w < -0.5*$y) { 20464 $c->yview(scroll => -$senkrecht, 'units'); # N 20465 } elsif ($x+0.5*$w < 2*$y) { 20466 $c->yview(scroll => $senkrecht, 'units'); # S 20467 $c->xview(scroll => $senkrecht, 'units'); # E 20468 } elsif ($x-1.5*$w < -2*$y) { 20469 $c->yview(scroll => -$senkrecht, 'units'); # N 20470 $c->xview(scroll => $senkrecht, 'units'); # E 20471 } else { 20472 $c->xview(scroll => $senkrecht, 'units'); # E 20473 } 20474 } 20475} 20476 20477### AutoLoad Sub 20478sub check_font { 20479 my $font = shift; 20480 eval { $top->Label(-font => $font)->destroy }; 20481 $@ eq ''; 20482} 20483 20484sub IncBusy { 20485 my($top, %args) = @_; 20486 return if !Tk::Exists($top); 20487 20488 if (!$top->{'Busy'}) { 20489 # Explicitely check for Windows - Tk::InputO might be install e.g. 20490 # in a cygwin install for Tk/X11 and fail then if Tk/MSWin32 is 20491 # used. 20492 if ($Tk::platform ne 'MSWin32' && eval q{ require Tk::InputO; 1 }) { 20493 for my $t ($top, values(%toplevel)) { 20494 next if !Tk::Exists($t); 20495 next if $args{-except} && $args{-except}{$t}; 20496 my $io = (Tk::Exists($t->{'BBBikeBusyIO'}) 20497 ? $t->{'BBBikeBusyIO'} 20498 : $t->InputO); 20499 $io->configure(-cursor => (defined $args{-cursor} ? $args{-cursor} : 'watch')); 20500 $io->place('-x' => 0, '-y' => 0, -relwidth => 1, -relheight => 1); 20501 $io->idletasks; 20502 $t->{'BBBikeBusy'} = 1; 20503 $t->{'BBBikeBusyIO'} = $io; 20504 } 20505 } else { 20506 # see "Busy" changes in TkChange.pm 20507 my $except = delete $args{-except}; 20508 if ($except) { 20509 # In this case we must not use the -recurse option, as 20510 # usually using -except means that there's a "cancel" window 20511 # which has to be accessible all the time 20512 $top->Busy(%args); 20513 } else { 20514 $top->Busy(-recurse => 1, %args); 20515 } 20516 } 20517 } 20518 $top->{'BusyCount'}++; 20519} 20520 20521sub DecBusy { 20522 my($top) = @_; 20523 return if !Tk::Exists($top); 20524 $top->{'BusyCount'}-- if $top->{'BusyCount'} > 0; 20525 if ($top->{'BusyCount'} < 1) { 20526 if ($top->{'BBBikeBusyIO'}) { 20527 for my $t ($top, values(%toplevel)) { 20528 next if !Tk::Exists($t) || 20529 !Tk::Exists($t->{'BBBikeBusyIO'}); 20530 $t->{'BBBikeBusyIO'}->placeForget; 20531 } 20532 delete $top->{'BBBikeBusy'}; 20533 } else { 20534 $top->Unbusy; 20535 } 20536 } 20537} 20538 20539### AutoLoad Sub 20540sub redisplay_top { 20541 my($top, $name, %args) = @_; 20542 my $force = delete $args{-force}; 20543 my $deiconify = (exists $args{-deiconify} ? delete $args{-deiconify} : 1); 20544 my $raise = (exists $args{-raise} ? delete $args{-raise} : 1); 20545 my $transient = (exists $args{-transient} ? delete $args{-transient} : 1); 20546 my $geometry = delete $args{-geometry}; 20547 if (!exists $args{-class}) { 20548 $args{-class} = "Bbbike Window"; 20549 } 20550 my $t = $toplevel{$name}; 20551 my $exists = 0; 20552 if (defined $t && Tk::Exists($t)) { 20553 if ($force) { 20554 $t->destroy; 20555 delete $toplevel{$name}; 20556 } else { 20557 $exists = 1; 20558 } 20559 } 20560 if ($exists) { 20561 $t->deiconify if $deiconify; 20562 # win32 ben�tigt zus�tzliches raise 20563 $t->raise if $raise; 20564 undef; 20565 } else { 20566 $toplevel{$name} = $top->Toplevel(%args); 20567 $toplevel{$name}->geometry($geometry) if $geometry; 20568 set_as_toolwindow($toplevel{$name}) if $transient; 20569 $toplevel{$name}->OnDestroy(sub { delete $toplevel{$name} }); 20570 $toplevel{$name}; 20571 } 20572} 20573 20574sub pending { 20575 my($bool, @types) = @_; 20576 if ($bool) { 20577 foreach (@types) { 20578 if (defined $immediate{$_}) { 20579 if ($immediate{$_} == 1) { 20580 update($_); 20581 } elsif ($immediate{$_} == 2) { 20582 $pending{$_}++; 20583 delayed_sub(sub { update() }, -name => 'pending'); 20584 } 20585 } else { 20586 $pending{$_}++; 20587 } 20588 } 20589 } 20590} 20591 20592sub update { 20593 my $type = shift; 20594 my @types; 20595 if (defined $type) { 20596 @types = ($type); 20597 } else { 20598 @types = keys %pending; 20599 } 20600 foreach $type (@types) { 20601 if ($type =~ /^replot-(.*)-(.*)$/) { 20602 my($str_p, $elem) = ($1, $2); 20603 plot($str_p,$elem); 20604 } elsif ($type eq 'recalc-net') { 20605 make_net(); 20606 read_sperre_tragen() unless $lowmem; # XXX should be called automatically, maybe? 20607 } else { 20608 die "Unknown update type: $type"; 20609 } 20610 } 20611} 20612 20613### AutoLoad Sub 20614sub calc_ampel_optimierung { 20615 return if !$ampel_optimierung; 20616 if ($average_v == -1) { 20617 # manuelle Eingabe, keine Berechnung notwendig... 20618 status_message(Mfmt("Einstellungen: verlorene Strecke pro Ampel: %d m", $lost_strecke_per_ampel), "info"); 20619 } else { 20620 require Ampelschaltung; 20621 my $speed = 20; 20622 if ($average_v != 0) { 20623 $speed = $average_v; 20624 } else { 20625 if ($active_speed_power{Type} eq 'speed') { 20626 $speed = $speed[$active_speed_power{Index}]; 20627 } elsif ($active_speed_power{Type} eq 'power' and $bikepwr) { 20628 my $bp_obj = new BikePower; 20629 $bp_obj->given('P'); 20630 $bp_obj->power($power[$active_speed_power{Index}]); 20631 $bp_obj->calc; 20632 $speed = float_prec($bp_obj->velocity*3.6, 1); 20633 } 20634 } 20635 my %res = Ampelschaltung::get_lost($speed, $beschleunigung); 20636 $lost_time_per_ampel{X} = $res{-zeit}; # XXX F 20637 $lost_strecke_per_ampel = $res{-strecke}; 20638 status_message(Mfmt("Einstellungen f�r %s km/h: verlorene Zeit pro Ampel: %s s, verlorene Strecke pro Ampel: %d m", $speed, float_prec($lost_time_per_ampel{X}, 1), $lost_strecke_per_ampel), "info"); # XXX F 20639 } 20640} 20641 20642sub now_time_hires { Tk::timeofday() } 20643 20644# evtl. utimes benutzen 20645sub cache_decider_init { $cache_decider_time = now_time_hires() } 20646 20647sub cache_decider { 20648 die "cache_decider on empty cache_decider_time scalar" 20649 if !defined $cache_decider_time; 20650 my $now = now_time_hires(); 20651 my $r = ($now - $cache_decider_time > $min_cache_decider_time); 20652 if ($verbose && $r) { 20653 warn "Using cache (" . ($now - $cache_decider_time) . " s)!\n"; 20654 } 20655 undef $cache_decider_time; 20656 $r; 20657} 20658 20659### AutoLoad Sub 20660sub add_last_loaded { 20661 my($file, $last_loaded_obj, $add_def) = @_; 20662 $add_def = "" if !defined $add_def; 20663 eval { 20664 require File::Spec; 20665 $file = File::Spec->canonpath($file); 20666 $file = File::Spec->rel2abs($file); 20667 }; 20668 my $max = $last_loaded_obj->{Max} || 4; # maximale Anzahl in @last_loaded 20669 my $i; 20670 for($i = 0; $i <= $#{ $last_loaded_obj->{List} }; $i++) { 20671 my($file_part) = $last_loaded_obj->{List}->[$i] =~ /^([^\t]*)/; 20672 if ($file_part eq $file) { 20673 splice @{ $last_loaded_obj->{List} }, $i, 1; 20674 $i--; 20675 } 20676 } 20677 unshift @{ $last_loaded_obj->{List} }, $file . $add_def; 20678 splice @{ $last_loaded_obj->{List} }, $max 20679 if @{ $last_loaded_obj->{List} } > $max; 20680 update_last_loaded_menu($last_loaded_obj); 20681 if ($os eq 'win') { 20682 require Win32Util; 20683 Win32Util::add_recent_doc($file); 20684 } 20685} 20686 20687sub load_last_loaded { 20688 my $last_loaded_obj = shift; 20689 undef @{ $last_loaded_obj->{List} }; 20690 if (open(LAST, $last_loaded_obj->{File})) { 20691 while(<LAST>) { 20692 chomp; 20693 s/\r//g; # DOS-Newlines entfernen (kann passieren!) 20694 push @{ $last_loaded_obj->{List} }, $_; 20695 } 20696 close LAST; 20697 update_last_loaded_menu($last_loaded_obj); 20698 } 20699} 20700 20701sub save_last_loaded { 20702 my $last_loaded_obj = shift; 20703 if (@{ $last_loaded_obj->{List} } && open(LAST, ">$last_loaded_obj->{File}")) { 20704 print LAST join("\n", @{ $last_loaded_obj->{List} }), "\n"; 20705 close LAST; 20706 } 20707} 20708 20709sub update_last_loaded_menu { 20710 my $last_loaded_obj = shift; 20711 my $last_loaded_menu = $last_loaded_obj->{Menu}; 20712 return unless $last_loaded_menu; 20713 if (!Tk::Exists($last_loaded_menu)) { 20714 die "XXX Can't update last loaded menu $last_loaded_menu"; 20715 } 20716 $last_loaded_menu->delete(0, 'end'); 20717 if (!@{ $last_loaded_obj->{List} }) { 20718 $last_loaded_menu->command(-label => "Flaschen leer",# kein M 20719 -state => 'disabled', 20720 -font => $font{'bold'}); 20721 } else { 20722 $last_loaded_menu->command(-label => $last_loaded_obj->{Title}, 20723 -state => 'disabled', 20724 -font => $font{'bold'}); 20725 foreach my $_file (@{ $last_loaded_obj->{List} }) { 20726 my($file, @args) = split /\t/, $_file; 20727 $last_loaded_menu->command(-label => $file, 20728 -command => [$last_loaded_obj->{Cb}, $file, @args], 20729 ); 20730 } 20731 } 20732} 20733 20734### AutoLoad Sub 20735sub fast_settings { 20736 foreach (keys %init_str_draw) { 20737 $init_str_draw{$_} = 0; 20738 $str_outline{$_} = 0; 20739 } 20740 foreach (keys %init_p_draw) { 20741 $init_p_draw{$_} = 0; 20742 } 20743 $show_grade = 0; 20744 $use_logo = 0; 20745 undef $center_on_str; 20746 undef $center_on_coord; 20747 $init_choose_street = 0; 20748 $autosave_opts = 0; # besser ist's 20749 $do_activate_temp_blockings = 0; 20750} 20751 20752sub set_mouse_desc { 20753 if ($special_edit eq 'radweg') { 20754 $mouse_text[1] = M"Radweg editieren"; 20755 $mouse_text[2] = M"Letzte Aktion wiederholen"; 20756 $mouse_text[3] = ''; 20757 } elsif ($special_edit eq 'ampel') { 20758 $mouse_text[1] = M"Ampel editieren"; 20759 $mouse_text[2] = $mouse_text[3] = ''; 20760 } else { 20761 $mouse_text[1] = M"Punkt zur Route hinzuf�gen\nMit Alt oder Shift: Mauscursor muss sich nicht �ber einer Stra�e befinden\nZiehen der Maus: Bewegen der Karte"; 20762 my $label = $b2_mode_desc{$b2_mode}; 20763 if (defined $label) { 20764 $mouse_text[2] = $label; 20765 } else { 20766 $mouse_text[2] = "???"; 20767 } 20768 if ($right_is_popup) { 20769 $mouse_text[3] = M"Popup-Men�"; 20770 } else { 20771 $mouse_text[3] = M"Gesamte Route l�schen"; 20772 } 20773 } 20774} 20775 20776sub change_font { 20777 my($font_type) = @_; 20778 $font_type = "normal" if !$font_type; 20779 eval { 20780 require Tk::FontDialog; 20781 Tk::FontDialog->VERSION(0.06); # -fixedfont... 20782 }; 20783 if ($@) { 20784 return if !perlmod_install_advice('Tk::FontDialog'); 20785 } 20786 20787 my %fd_args; 20788 if ($font_type eq 'fixed') { 20789 $fd_args{'-fixedfont'} = 1; 20790 $fd_args{'-fixedfontsbutton'} = 0; 20791 $fd_args{'-initfont'} = $font{'fixed'}; 20792 } 20793 my $fedit = $top->FontDialog(%fd_args); 20794 my $f = $fedit->Show; 20795 if (defined $f) { 20796 if ($font_type eq 'fixed') { 20797 $font{'fixed'} = $f; # XXX probably this does not re-set existing labels 20798 $fixed_font_family = $top->fontActual($font{'fixed'}, '-family'); 20799 # XXX note that there's no way to set the point size 20800 } else { 20801 my $normal_font = $f; 20802 set_fonts($normal_font); 20803 $top->optionAdd("*font" => $font{normal}, 'userDefault'); 20804 } 20805 } 20806} 20807 20808sub size2px { 20809 my $size = shift; 20810 $size < 0 ? -$size : int(0.5 + $size*($top_dpi/72)); 20811} 20812 20813sub size2pt { 20814 my $size = shift; 20815 $size >= 0 ? $size : int(0.5 - $size/($top_dpi/72)); 20816} 20817 20818# A part of set_fonts which has to be called very early 20819sub set_sans_serif_font_family { 20820 $has_xft = 0; 20821 $sans_serif_font_family = "Helvetica"; 20822 eval { 20823 require Tk::Config; 20824 $has_xft = $Tk::Config::xlib =~ /-lXft\b/; 20825 if ($has_xft) { 20826 $sans_serif_font_family = "sans-serif"; 20827 } 20828 }; 20829} 20830 20831# Create the fontset for bbbike. Use $std_font (which must be a 20832# current Tk font name, not a font specification) as default normal 20833# font, or, if not defined, use the system default (e.g. from the 20834# option database). The fontset is stored to the global hash %font. 20835# $top is the main window. 20836sub set_fonts { 20837 my $std_font = shift; 20838 # backward compatibility with Tk 402: 20839 if ($Tk::VERSION <= 402.004) { 20840 set_fonts_402(); 20841 } else { 20842 # XXX check it under all platforms! 20843 my $get_std_font = sub { 20844 my $std_font = $top->optionGet('font', 'Font'); 20845 if (!defined $std_font || $std_font eq '') { 20846 my $l = $top->Label; 20847 $std_font = $l->cget(-font); 20848 if ($^O eq 'MSWin32') { 20849 # Using MS Sans Serif is probably not correct 20850 # See also: http://www.tcl.tk/cgi-bin/tct/tip/64.html 20851 my(%std_font) = $l->fontActual($std_font); 20852 if ($std_font{-family} =~ m{ms sans serif}i) { 20853 my %font_families = map{(lc($_),1)} $top->fontFamilies; 20854 my $new_family = ( exists $font_families{tahoma} ? "tahoma" 20855 : exists $font_families{arial} ? "arial" : undef 20856 ); 20857 if (defined $new_family) { 20858 $std_font = $top->fontCreate(-family => $new_family, 20859 -size => size2pt($std_font{-size})); 20860 } 20861 } 20862 } 20863 $l->destroy; 20864 } 20865 $std_font; 20866 }; 20867 20868 my $font_from_user = 0; # true, if from options or set interactively 20869 my $font_size_from_user = 0; 20870 if (!$std_font) { 20871 # $font_family, $font_size, $font_weight from cmdline 20872 if (defined $font_family && $font_family ne "" && !$kde) { 20873 if (!defined $font_size) { 20874 my $std_font = $get_std_font->(); 20875 $font_size = $top->fontActual($std_font, '-size'); 20876 } else { 20877 $font_size_from_user = 1; 20878 } 20879 $font_from_user = 1; 20880 my(%a) = (-family => $font_family); 20881 if (defined $font_size && $font_size =~ /^-?\d+$/) { 20882 $a{-size} = $font_size; 20883 } elsif (defined $font_size) { 20884 warn "Font size defined as <$font_size>, but does not match pattern, so fallback to default size..."; 20885 $a{-size} = $font_size = 10; 20886 } 20887 if (defined $font_weight && $font_weight ne '') { 20888 $a{-weight} = $font_weight; 20889 } 20890 eval { 20891 $std_font = $top->fontCreate(%a); 20892 }; 20893 if ($@) { 20894 my $err = $@; 20895 $std_font = "helvetica 10"; 20896 print STDERR Mfmt("Fehler beim Definieren des Zeichensatzes:\n" . 20897 "%s\n" . 20898 "Fallback auf den Zeichensatz <%s>.\n", 20899 $err, $std_font) . 20900 wrap("", "", 20901 Mfmt("Dieser Fehler kann m�glicherweise durch Korrigieren der Eintr�ge <fontfamily> und <fontheight> in <%s> oder <*font> in <~/.Xdefaults> behoben werden.", 20902 catfile($bbbike_configdir, "config"))) . 20903 "\n"; 20904 } 20905 $top->optionAdd('*font' => $std_font, 'userDefault'); 20906 } else { 20907 $std_font = $get_std_font->(); 20908 } 20909 } else { 20910 $font_from_user = $font_size_from_user = 1; 20911 } 20912 20913 if (exists $font{'normal'} && $std_font) { 20914 $top->fontConfigure($font{normal}, $top->fontActual($std_font)); 20915 } elsif ($std_font) { 20916 $font{'normal'} = $top->fontCreate($top->fontActual($std_font)); 20917 } else { 20918 $font{'normal'} = $top->fontCreate; 20919 } 20920 20921 my %normal_attr = $top->fontActual($font{'normal'}); 20922 20923 my $size = $normal_attr{'-size'}; # points or pixels depending on Tk ver 20924 my $px = size2px($size); 20925 my $pt = size2pt($size); 20926 my $win_width = @want_extends ? $want_extends[GEOMETRY_WIDTH] : $top->width; 20927 if ($win_width <= 800 && $pt >= 10 && !$font_size_from_user) { 20928## XXX This is evil: because the fontsize will be from time to time smaller 20929## if the use resizes below the limits and then above the limits. 20930## On the other side, this will result in too big fonts on small 20931## displays. Solution? 20932 if ($win_width <= 320) { 20933 $pt = $pt*8/14; 20934 } elsif ($win_width <= 640) { 20935 $pt = $pt*10/14; 20936 } else { 20937 $pt = $pt*12/14; 20938 } 20939 $top->fontConfigure($font{'normal'}, -size => sprintf("%.f", $pt)); 20940 } 20941 20942 # This looks like a no-op, as $font{normal} was usually 20943 # determined from the default font in the option database. But 20944 # with this setting the _Tk font name_ is forced to be used. 20945 # This is a requirement to see immediate effects when changing 20946 # the font using FontDialog. 20947 $top->optionAdd('*font' => $font{'normal'}, 'userDefault'); 20948 20949 foreach (qw(veryhuge huge verylarge large bold 20950 reduced small tiny fixed standard fix15)) { 20951 if (exists $font{$_}) { 20952 $top->fontConfigure($font{$_}, $top->fontActual($font{'normal'})); 20953 } else { 20954 $font{$_} = $top->fontCreate($top->fontActual($font{'normal'})); 20955 } 20956 } 20957 20958 my $minfs = sub { 20959 my $fs = shift; 20960 $fs = 6 if ($fs < 6); 20961 $fs; 20962 }; 20963 20964 $top->fontConfigure($font{'bold'}, 20965 -size => sprintf("%.f", $minfs->($pt)), 20966 -weight => 'bold'); 20967 $top->fontConfigure($font{'fix15'}, # exactly 15 pixels height (if not $small_icons in effect) 20968 -size => ($small_icons ? -8 : -15)); 20969 $top->fontConfigure($font{'tiny'}, 20970 -size => sprintf("%.f", $minfs->($pt*8/14))); 20971 $top->fontConfigure($font{'small'}, 20972 -size => sprintf("%.f", $minfs->($pt*10/14))); 20973 $top->fontConfigure($font{'reduced'}, 20974 -size => sprintf("%.f", $minfs->($pt*12/14))); 20975 $top->fontConfigure($font{'large'}, 20976 -size => sprintf("%.f", $minfs->($pt*18/14))); 20977 $top->fontConfigure($font{'verylarge'}, 20978 -size => sprintf("%.f", $minfs->($pt*24/14))); 20979 $top->fontConfigure($font{'huge'}, 20980 -size => sprintf("%.f", $minfs->($pt*28/14))); 20981 $top->fontConfigure($font{'veryhuge'}, 20982 -size => sprintf("%.f", $minfs->($pt*36/14))); 20983 $top->fontConfigure($font{'standard'}, 20984 -size => $standard_height, 20985 -slant => 'roman', 20986 -underline => 0, 20987 -overstrike => 0); 20988 if ($pt >= 8) { 20989 $top->fontConfigure($font{fixed}, -family => $fixed_font_family); 20990 } else { 20991 $font{'fixed'} = "5x7"; # XXX really necessary? 20992 } 20993 20994## Here from a Win98 session what fonts are readable 20995## 20996# Arial: unterhalb von 5pt: nicht zu gebrauchen 20997# 5pt - 6pt: noch lesbar, aber einige Buchstaben 20998# sehen kaputt aus 20999# 7pt: OK 21000# Courier New: 5pt: kaum lesbar 21001# 6pt: sieht ziemlich schlecht aus 21002# 7pt: OK 21003# Lucida Console: unterhalb von 5pt: nicht zu gebrauchen 21004# 5pt: erstaunlich gut 21005# 6pt und mehr: OK 21006# MS Sans Serif: 9pt scheint die Minimalgr��e zu sein 21007# MS Serif: 6pt ist die Minimalgr��e und recht gut lesbar 21008# System: 16pt scheint die Minimalgr��e zu sein 21009# Tahoma: unterhalb von 5pt: nicht zu gebrauchen 21010# 5pt - 6pt: noch lesbar, aber einige Buchstaben 21011# sehen kaputt aus 21012# 7pt: OK 21013# Times New Roman:unterhalb von 10px (6pt): nicht zu gebrauchen 21014# 10px (6pt): ein paar Buchstaben sehen komisch aus 21015# 12px (7pt): OK, wenn auch etwas gequetscht 21016# Verdana: unterhalb von 5pt: nicht zu gebrauchen 21017# 5pt - 6pt: noch lesbar, aber einige Buchstaben 21018# sehen kaputt aus 21019# 7pt: OK 21020# Pixel <-> Point (bei Times New Roman) 21021# 3 2 21022# 4 2 21023# 5 4 21024# 6 5 21025# 7 5 21026# 8 5 21027# 9 5 21028# 10 6 21029# 11 6 21030# 12 7 21031# 13 8 21032# 14 8 21033# 15 9 21034# 21035 my %min_px = 21036 ('helvetica' => 8, 21037 'times' => 10, 21038 'times new roman' => 10, # 12 w�re eigentlich besser 21039 'lucida' => 8, 21040 'new century schoolbook' => 8, 21041 'fixed' => 7, 21042 'arial' => 8, # at this size some characters already look somewhat broken (seen on Win98, 800x600 screen) 21043 'courier new' => 8, 21044 '__DEFAULT__' => 8, 21045 ); 21046 21047 # Resize if necessary, to prevent fonts from being too small. 21048 # This is from looking at readable fonts under the iPAQ. I found 21049 # that Lucida can produce the smallest readable fonts. 21050 while(my($k,$v) = each %font) { 21051 my $family = lc $top->fontActual($v, '-family'); 21052 my $min_px = $min_px{$family} || $min_px{__DEFAULT__}; 21053 my $current_size = $top->fontActual($v, "-size"); 21054 my $current_px = size2px($current_size); 21055 if ($current_px < $min_px) { 21056 $top->fontConfigure($v, -size => -$min_px); 21057 } 21058 } 21059 } 21060 21061 # Array of sorted fonts (by size) used e.g. in 21062 # get_orte_label_font() 21063 @font = qw(tiny small reduced normal large verylarge huge veryhuge); 21064 21065 for my $font (@font) { 21066 my $font_key = $font."-italic"; 21067 eval { 21068 if (exists $font{$font_key}) { 21069 $top->fontConfigure($font{$font_key}, 21070 $top->fontActual($font{$font}, -slant => "italic"), 21071 ); 21072 } else { 21073 $font{$font_key} = $top->fontCreate($top->fontActual($font{$font}), -slant => "italic"); 21074 } 21075 }; 21076 if ($@ || !$font{$font_key}) { 21077 # fallback to non-italic variant 21078 $font{$font_key} = $font{$font}; 21079 } 21080 } 21081} 21082 21083# Set image, if available, otherwise the fallback label 21084sub image_or_text { 21085 my($image, $text) = @_; 21086 if (defined $image) { 21087 (-image => $image); 21088 } else { 21089 (-text => $text); 21090 } 21091} 21092 21093# Doc? 21094### AutoLoad Sub 21095sub image_from_file { 21096 my($top, $file, %args) = @_; 21097 my $mimetype = $args{'-mimetype'}; 21098 my $colormode = $args{'-colormode'} || 'color'; 21099 21100 if ($file =~ /\.jpe?g$/i || 21101 (defined $args{-mimetype} and $args{-mimetype} eq 'image/jpeg')) { 21102 eval { require Tk::JPEG }; 21103 if ($@) { 21104 return if !perlmod_install_advice('Tk::JPEG'); 21105 } 21106 } elsif ($file =~ /\.png$/i || 21107 (defined $args{-mimetype} and $args{-mimetype} eq 'image/png')) { 21108 eval { require Tk::PNG }; 21109 if ($@) { 21110 return if !perlmod_install_advice('Tk::PNG'); 21111 } 21112 } 21113 21114 if ($colormode eq 'mono') { 21115 $top->Bitmap(-file => $file); 21116 } elsif ($colormode eq 'pixmap') { 21117 $top->Pixmap(-file => $file); 21118 } elsif ($colormode eq 'gray') { 21119 $top->Photo(-file => $file, -palette => 8); 21120 } else { 21121 $top->Photo(-file => $file); 21122 } 21123} 21124 21125# Load the image from file $file. Do nothing if $lowmem mode 21126# is set. If the -persistent is set, then store the image into the 21127# persistent %photo hash for caching. -name can be set 21128# for a Tcl-styled image name. In $small_icons mode every 21129# image is shrinked to half width/height. 21130# 21131# .xpm files are loaded into a Tk::Pixmap object, not Tk::Photo 21132# (unless $small_icons is active) 21133# 21134# .svg files are converted using the svg2photo function. In 21135# this case, the options -w and -h are mandatory. 21136sub load_photo { 21137 my($top, $file, %args) = @_; 21138 if (!defined $file) { 21139 require Data::Dumper; 21140 die "File missing in load_photo, called in " . Dumper(caller); 21141 } 21142 21143 my $cache_key = $file; 21144 my %photo_args; 21145 for my $key (qw(-palette -gamma)) { 21146 if (exists $args{$key}) { 21147 my $val = $photo_args{$key} = delete $args{$key}; 21148 $cache_key .= "-$key:$val"; 21149 } 21150 } 21151 for my $key (qw(-w -h)) { 21152 if (exists $args{$key}) { 21153 my $val = $args{$key}; 21154 $cache_key .= "-$key:$val"; 21155 } 21156 } 21157 return $photo{$cache_key} if exists $photo{$cache_key}; 21158 21159 my $photo; 21160 unless ($lowmem) { 21161 eval { 21162 my @name = exists $args{-name} ? ($args{-name}) : (); 21163 my $do_subsample = $small_icons; 21164 if ($file =~ m{\.xpm$}i && !$small_icons) { 21165 # Pixmap seem to be more memory-efficient, but it's 21166 # not possible to do subsample operations (in case of 21167 # $small_icons) 21168 $photo = $top->Pixmap(@name, -file => Tk::findINC($file)); 21169 } else { 21170 my $path; 21171 if (file_name_is_absolute($file)) { 21172 $path = $file; 21173 } else { 21174 for my $try_file ((-d "$datadir/images" ? "$datadir/images/$file" : ()), 21175 "$FindBin::RealBin/images/$file", 21176 ) { 21177 my $try_path = try_image_suffix($try_file); 21178 if (defined $try_path && -r $try_path) { 21179 $path = $try_path; 21180 last; 21181 } 21182 } 21183 if (!defined $path) { 21184 warn "Could not find photo, try <$file> in some \@INC dirs...\n"; # XXX should never happen? 21185 $path = Tk::findINC($file); 21186 } 21187 } 21188 if ($path) { 21189 if ($path =~ m{\.svg$}i) { 21190 my $w = delete $args{-w}; 21191 die "-w is mandatory for svg files" if !$w; 21192 my $h = delete $args{-h}; 21193 die "-h is mandatory for svg files" if !$h; 21194 if ($small_icons) { 21195 $w /= 2; 21196 $h /= 2; 21197 $do_subsample = 0; 21198 } 21199 $photo = svg2photo($path, $w, $h); 21200 } else { 21201 $photo = $top->Photo(@name, -file => $path, %photo_args); 21202 } 21203 } 21204 } 21205 if ($do_subsample && $photo) { 21206 # XXX setting of @name missing 21207 my $small_photo = $top->Photo(-width => $photo->width/2, 21208 -height => $photo->height/2, 21209 %photo_args); 21210 $small_photo->copy($photo, -subsample => 2, 2); 21211 $photo->delete; 21212 $photo = $small_photo; 21213 } 21214 };warn $@ if $@; 21215 } 21216 if ($args{-persistent}) { 21217 $photo{$cache_key} = $photo; 21218 } 21219 $photo; 21220} 21221 21222sub load_cursor { 21223 my($def) = @_; 21224 return if $Tk::platform eq 'MSWin32'; # no support for custom cursors yet 21225 my $key = my $lang_def = $def; 21226 if ($def eq 'ziel') { 21227 $lang_def = M($def); 21228 } 21229 my $base = $lang_def . '_ptr.xbm'; 21230 my $xbm = Tk::findINC($base); 21231 if (!defined $xbm) { 21232 print STDERR Mfmt("Die Datei <%s> existiert nicht.", $base) . "\n"; 21233 } elsif (-r $xbm) { 21234 my $mask = Tk::findINC($lang_def . '_ptr_mask.xbm'); 21235 if (-r $mask) { 21236 $cursor{$key} = $xbm; 21237 $cursor_mask{$key} = $mask; 21238 } 21239 } 21240} 21241 21242sub load_stipple { 21243 my($def) = @_; 21244 return $stipple{$def} if exists $stipple{$def}; 21245 if ($def =~ m{^gray(?:25|50|75)$}) { # some builtins 21246 $stipple{$def} = $def; 21247 } else { 21248 $stipple{$def} = Tk::findINC($def); 21249 if ($stipple{$def}) { 21250 $stipple{$def} = '@' . $stipple{$def}; 21251 } 21252 } 21253 $stipple{$def}; 21254} 21255 21256# do a correct isa call on scrolled widgets 21257sub subw_isa { 21258 my($w, $isa) = @_; 21259 if ($w->Subwidget('scrolled')) { 21260 $w = $w->Subwidget('scrolled'); 21261 } 21262 $w->isa($isa); 21263} 21264 21265# Callback bei einem Drop-Vorgang. 21266# Die Datei wird per load_save_route() geladen. 21267### AutoLoad Sub 21268sub accept_drop { 21269 my($c, $seln) = @_; 21270 my $filename; 21271 my @targ = $c->SelectionGet('-selection'=>$seln,'TARGETS'); 21272 foreach (@targ) { 21273 if (/FILE_NAME/) { 21274 $filename = $c->SelectionGet('-selection'=>$seln,'FILE_NAME'); 21275 last; 21276 } 21277 if ($os eq 'win' && /STRING/) { 21278 $filename = $c->SelectionGet('-selection'=>$seln,$_); 21279 last; 21280 } 21281 } 21282 if (defined $filename) { 21283 if ($filename =~ /\.bbd/i) { 21284 plot_layer('str', $filename); 21285 } else { 21286 load_save_route(0, $filename); 21287 } 21288 } 21289} 21290 21291 21292# Return the start and goal streets of the current route 21293### AutoLoad Sub 21294sub get_route_description { 21295 my(%args) = @_; 21296 my $with_via = exists $args{-withvia} ? delete $args{-withvia} : 1; 21297 if (%args) { 21298 warn "WARNING: get_route_description called with extra arguments: " . join(" ", %args); 21299 } 21300 21301 my $text = ""; 21302 my @search_route = @{ get_act_search_route() }; 21303 if (@search_route) { 21304 $text = $search_route[0][StrassenNetz::ROUTE_NAME]; 21305 if ($with_via && @search_route_points > 2) { # do we have a via? 21306 # XXX This is a simple solution. A better one use the 21307 # farthest point instead the point in the middle of the 21308 # list. 21309 $text .= " - " . $search_route[@search_route/2][StrassenNetz::ROUTE_NAME]; 21310 } 21311 $text .= " - " . $search_route[-1][StrassenNetz::ROUTE_NAME]; 21312 } 21313 $text; 21314} 21315 21316# Return the approximated center of the polyline. 21317# Coordinates of the polygon are supplied in @koord (flat list of x and y 21318# values). 21319# If @koord is just a point then return it. 21320### AutoLoad Sub 21321sub get_polyline_center { 21322 my(@koord) = @_; 21323 return @koord if @koord == 2; 21324 my $len = 0; 21325 for(my $i=2; $i<$#koord; $i+=2) { 21326 $len += Strassen::Util::strecke([@koord[$i-2,$i-1]], 21327 [@koord[$i, $i+1]]); 21328 } 21329 my $len0 = 0; 21330 for(my $i=2; $i<$#koord; $i+=2) { 21331 $len0 += Strassen::Util::strecke([@koord[$i-2,$i-1]], 21332 [@koord[$i, $i+1]]); 21333 if ($len0 > $len/2) { 21334 # XXX ungenau, besser machen! 21335 return (($koord[$i-2]-$koord[$i])/2+$koord[$i], 21336 ($koord[$i-1]-$koord[$i+1])/2+$koord[$i+1]); 21337 } 21338 } 21339 warn "Fallback for get_polyline_center, should not happen. Coords are @koord"; 21340 (($koord[2]-$koord[0])/2+$koord[0], 21341 ($koord[3]-$koord[1])/2+$koord[1]); 21342} 21343 21344### AutoLoad Sub 21345sub get_bbox_area { 21346 my($item) = @_; 21347 my(@bbox) = $c->bbox($item); 21348 abs(($bbox[2]-$bbox[0]) * ($bbox[3]-$bbox[1])); 21349} 21350 21351# Erzeugt eine Backupdatei 21352### AutoLoad Sub 21353sub make_backup { 21354 my $file = shift; 21355 if (-e $file) { 21356 if (-f $file) { 21357 my $backup = "$file~"; 21358 rename $file, $backup; 21359 } else { 21360 status_message(Mfmt("%s ist keine g�ltige Datei, kein Backup.", 21361 $file), 21362 'err'); 21363 } 21364 } 21365} 21366 21367use your qw($StrassenNetz::VERBOSE $Strassen::VERBOSE $wettermeldung2::VERBOSE 21368 $Tk::SRTProgress::VERBOSE 21369 $Telefonbuch::VERBOSE $GfxConvert::VERBOSE $Hooks::VERBOSE 21370 $FURadar::VERBOSE); 21371 21372# Setzt die VERBOSE-Variable in den geladenen Modulen 21373### AutoLoad Sub 21374sub set_verbose { 21375 Strassen::set_verbose($verbose); 21376 $wettermeldung2::VERBOSE = $verbose; 21377 $Tk::SRTProgress::VERBOSE = $verbose; 21378 $Telefonbuch::VERBOSE = $verbose; 21379 $GfxConvert::VERBOSE = $verbose; 21380 $Hooks::VERBOSE = $verbose; 21381 $FURadar::VERBOSE = $verbose; 21382 $PLZ::VERBOSE = $verbose; 21383} 21384 21385# crops the array in $want_extends to the limits in $extends 21386sub crop_geometry { 21387 my($want_extends, $extends) = @_; 21388 21389 # right/bottom limits 21390 my $x = $want_extends->[GEOMETRY_X] =~ /^-/ ? 21391 $top->screenwidth - $want_extends->[GEOMETRY_WIDTH] + $want_extends->[GEOMETRY_X] : 21392 $want_extends->[GEOMETRY_X]; 21393 my $y = $want_extends->[GEOMETRY_Y] =~ /^-/ ? 21394 $top->screenheight - $want_extends->[GEOMETRY_HEIGHT] + $want_extends->[GEOMETRY_Y] : 21395 $want_extends->[GEOMETRY_Y]; 21396 my($maxx) = $want_extends->[GEOMETRY_WIDTH] + $x; 21397 my($maxy) = $want_extends->[GEOMETRY_HEIGHT] + $y; 21398 21399 if ($x < $extends->[GEOMETRY_X]) { 21400 $want_extends->[GEOMETRY_X] = $extends->[GEOMETRY_X]; 21401 } 21402 if ($y < $extends->[GEOMETRY_Y]) { 21403 $want_extends->[GEOMETRY_Y] = $extends->[GEOMETRY_Y]; 21404 } 21405 if ($x + $want_extends->[GEOMETRY_WIDTH] > $extends->[GEOMETRY_WIDTH]) { 21406 $want_extends->[GEOMETRY_WIDTH] = $extends->[GEOMETRY_WIDTH] - $x; 21407 } 21408 if ($y + $want_extends->[GEOMETRY_HEIGHT] > $extends->[GEOMETRY_HEIGHT]) { 21409 $want_extends->[GEOMETRY_HEIGHT] = $extends->[GEOMETRY_HEIGHT] - $y; 21410 } 21411} 21412 21413sub parse_geometry_string { 21414 my $geometry = shift; 21415 my @extends = (0, 0, 0, 0); 21416 if ($geometry =~ /([-+]?\d+)x([-+]?\d+)/) { 21417 $extends[GEOMETRY_WIDTH] = $1; 21418 $extends[GEOMETRY_HEIGHT] = $2; 21419 } 21420 if ($geometry =~ /([-+]\d+)([-+]\d+)/) { 21421 $extends[GEOMETRY_X] = $1; 21422 $extends[GEOMETRY_Y] = $2; 21423 } 21424 @extends; 21425} 21426 21427# Alternative way to set geometry. 21428sub geometry { 21429 my($t, @extends) = @_; 21430 my $geometry = "$extends[GEOMETRY_WIDTH]x$extends[GEOMETRY_HEIGHT]"; 21431 $extends[GEOMETRY_X] = "+$extends[GEOMETRY_X]" if $extends[GEOMETRY_X] !~ /^[+-]/; 21432 $extends[GEOMETRY_Y] = "+$extends[GEOMETRY_Y]" if $extends[GEOMETRY_Y] !~ /^[+-]/; 21433 $geometry .= $extends[GEOMETRY_X] . $extends[GEOMETRY_Y]; 21434 $t->geometry($geometry); 21435} 21436 21437sub fix_geometry { 21438 my $geom_string = shift || $top->geometry; 21439 my(@extends) = parse_geometry_string($geom_string); 21440 $extends[GEOMETRY_HEIGHT] += ($top->wrapper)[1]; 21441 if ($^O eq 'MSWin32') { 21442 # This seems to be necessary at least on a Win98 machine 21443 # or maybe only on systems where wrapper[1] returns 0? 21444 # 20 should probably be replaced by the value of $SM_CYCAPTION, see Win32Util (19 on this system) 21445 $extends[GEOMETRY_HEIGHT] += 20; # get titlebar height (?) by API functions XXX 21446 } 21447 "$extends[GEOMETRY_WIDTH]x$extends[GEOMETRY_HEIGHT]" . 21448 ($extends[GEOMETRY_X] =~ m{^[+-]} ? '' : '+') . $extends[GEOMETRY_X] . 21449 ($extends[GEOMETRY_Y] =~ m{^[+-]} ? '' : '+') . $extends[GEOMETRY_Y]; 21450} 21451 21452# check if the toplevel is too large and resize, if appropriate 21453sub toplevel_checker { 21454 my($t) = @_; 21455 $t->update; 21456 my($sw,$sh) = ($t->screenwidth, $t->screenheight); 21457 my($x,$y,$w,$h) = ($t->x, $t->y, $t->width, $t->height); 21458 $w = $sw if ($w > $sw); 21459 $h = $sh if ($h > $sh); 21460 $x = 0 if ($x+$w > $sw || $x < 0); 21461 $y = 0 if ($y+$h > $sh || $y < 0); 21462 $t->geometry($w."x".$h."+$x+$y"); 21463} 21464 21465sub get_polar_location_of_route_end { 21466 return undef if !@realcoords; 21467 require Karte::Polar; 21468 my($px,$py) = $Karte::Polar::obj->standard2map(@{ $realcoords[-1] }); 21469 "$px,$py"; 21470} 21471 21472sub my_popup { 21473 my $t = shift; 21474 $t->withdraw; 21475 $t->Popup(@popup_style); 21476} 21477 21478sub optedit { 21479 my(%args) = @_; 21480 my $opt_edit = $top->{GetoptEditor}; 21481 if (Tk::Exists($opt_edit)) { 21482 $opt_edit->raise; 21483 if ($args{-page}) { 21484 $opt->raise_page($args{-page}); 21485 } 21486 return; 21487 } 21488 21489 # Hack for small screens. Should be a better solution in 21490 # Tk::Getopt. Unfortunately there's even no -font option 21491 # in Tk::Getopt, so try to use a option db hack. 21492 if ($top->screenwidth <= 11024) { 21493 my $font = $top->screenwidth <= 800 ? $font{small} : $font{reduced}; 21494 $top->optionAdd("*bbbikeOptionEditor*font" => $font); 21495 } 21496 21497 $opt_edit = $opt->option_editor 21498 ($top, 21499 Name => "bbbikeOptionEditor", # lowercase beginning! 21500 ($transient ? (-transient => $top) : ()), 21501 (!defined $ENV{LANG} || $ENV{LANG} =~ /^de/ ? 21502 (-string => {optedit => "Optionseditor", 21503 undo => "Undo", 21504 lastsaved => "Zuletzt gespeichert", 21505 save => "Speichern", 21506 defaults => "Voreinstellungen", 21507 ok => "Ok", 21508 oksave => "Ok", 21509 apply => "Anwenden", 21510 cancel => "Abbrechen", 21511 helpfor => "Hilfe f�r", 21512 } 21513 ) : ()), 21514 -buttons => ['oksave', 21515 #'defaults', # XXX defaults or not defaults??? 21516 #could be misleading, users might think that the 21517 #defaults just apply to the displayed page 21518 'cancel'], 21519 %args, # e.g. -page 21520 ); 21521 $top->{GetoptEditor} = $opt_edit; 21522} 21523 21524sub export_visible_map { 21525 my($fmt, $outfile) = @_; 21526 21527 if (!defined $outfile) { 21528 $outfile = $top->getSaveFile 21529 (-defaultextension => ".$fmt", 21530 -title => Mfmt('%s-Datei sichern', uc($fmt)), 21531 -initialdir => $save2_path); 21532 } 21533 return if !defined $outfile; 21534 $save2_path = dirname $outfile; 21535 21536 # Temporarily close all toplevels to make sure that the 21537 # canvas window is topmost (but it's still not perfect!) 21538 my $redisplay_toplevels; 21539 { 21540 my %withdrawn_toplevels; 21541 # $top->stackorder did not work under MSWin32 before Tk 804.028 (but ->can returned true!) 21542 my @stackorder = $Tk::platform ne "MSWin32" || $Tk::VERSION >= 804.028 ? $top->stackorder : (); 21543 $top->Walk(sub { 21544 my($w) = @_; 21545 if (Tk::Exists($w) && $w->isa("Tk::Wm") && eval { $w->state } eq 'normal') { 21546 $w->withdraw; 21547 $withdrawn_toplevels{$w->PathName()} = $w; 21548 } 21549 }); 21550 $redisplay_toplevels = sub { 21551 my %handled_toplevels; 21552 for my $tpn (reverse @stackorder) { 21553 if ($withdrawn_toplevels{$tpn}) { 21554 eval { $withdrawn_toplevels{$tpn}->deiconify }; 21555 $handled_toplevels{$tpn}++; 21556 } else { 21557 } 21558 } 21559 while(my($tpn, $w) = each %withdrawn_toplevels) { 21560 if (!$handled_toplevels{$tpn}) { 21561 eval { $w->deiconify }; 21562 } 21563 } 21564 }; 21565 } 21566 $top->raise; 21567 $top->update; 21568 $top->tk_sleep(1); # make sure the update was really done 21569 21570 my $imager_fmt = $fmt eq 'ppm' ? 'pnm' : $fmt; 21571 if ($devel_host && eval { 21572 require Imager; 21573 Imager->VERSION(0.62); 21574 die "Imager does not support image format <$imager_fmt>, use fallback...\n" 21575 if !grep { $imager_fmt eq $_ } Imager->write_types; 21576 require Imager::Screenshot; 21577 Imager::Screenshot->VERSION(0.005); 21578 1; 21579 }) { 21580 my $img; 21581 eval { 21582 ## This should work, but does not, because $widget->can("frame") seems 21583 ## to be always true 21584 ## XXX for Version 0.006 this will work: 21585 #$img = Imager::Screenshot::screenshot(widget => $c); 21586 #my $img = Imager::Screenshot::screenshot(widget => $c, decor => 0); 21587 $img = Imager::Screenshot::screenshot(($Tk::platform eq 'MSWin32' ? 'hwnd' : 'id'), 21588 hex $c->id); 21589 if ($img) { 21590 $img->write(file => $outfile, type => $imager_fmt) or $img = undef; 21591 } 21592 }; 21593 warn $@ if $@; 21594 $redisplay_toplevels->(); 21595 if (!$img) { 21596 status_message("Imager and Imager::Screenshot installed, but screenshot failed", "warn"); 21597 } else { 21598 return; 21599 } 21600 } 21601 21602 IncBusy($top); 21603 eval { 21604 my $in_fmt; 21605 my $tmpfile; 21606 my $bgcolor = sprintf('#%02x%02x%02x', map { $_/256 } $c->rgb($c->cget(-background))); 21607 my $NNcolor = sprintf('#%02x%02x%02x', map { $_/256 } $c->rgb($category_color{N})); 21608 my %args = 21609 (-mapcolor => 21610 {# Swap colors to avoid non-white background 21611 $bgcolor => '#ffffff', 21612 $NNcolor => $bgcolor, 21613 }, 21614 -res => $ps_image_res, 21615 -autocrop => 1, 21616 ); 21617 21618 my $post_processing_needed = 1; 21619 21620 require BBBikePrint; # for using_rotated_fonts 21621 if ((using_rotated_fonts() || 21622 $use_xwd_if_possible 21623 ) and 21624 $Tk::platform eq 'unix' 21625 and 21626 is_in_path("xwd") 21627 ) { 21628 21629 $args{-rotate} = -90 if $orientation eq 'portrait'; 21630 21631 $in_fmt = "xwd"; 21632 if ($fmt ne 'xwd') { 21633 require GfxConvert; 21634 GfxConvert::check($in_fmt, $fmt, $tmpfile, $outfile, %args); 21635 } else { 21636 $post_processing_needed = 0; 21637 } 21638 21639 $tmpfile = "/tmp/bbbike.$$.xwd"; 21640 $tmpfiles{$tmpfile}++; 21641 21642 my $deiconify_subs = withdraw_toplevels(); 21643 $top->raise; 21644 $top->update; 21645 system("xwd", "-out", "$tmpfile", "-id", $c->id); 21646 $_->() for (@$deiconify_subs); 21647 $top->bell; 21648 21649 } elsif ($fmt eq 'pdf' && 21650 !eval { 21651 require GfxConvert; 21652 GfxConvert::check($in_fmt, $fmt, $tmpfile, $outfile, %args); 21653 1; 21654 }) { 21655 pdf_export(-visiblemap => 1, -file => $outfile); 21656 $post_processing_needed = 0; 21657 } else { 21658 21659 $args{-rotate} = -90 if $orientation eq 'landscape'; 21660 $in_fmt = "ps"; 21661 21662 if ($fmt ne 'ps') { 21663 require GfxConvert; 21664 GfxConvert::check($in_fmt, $fmt, $tmpfile, $outfile, %args); 21665 } else { 21666 $post_processing_needed = 0; 21667 } 21668 21669 die M"Der Export wurde unterbrochen." 21670 if slow_postscript_generation(); 21671 21672 $tmpfile = create_postscript($c, 21673 -colormode => 'color', 21674 -rotate => 1, 21675 -scale_a4 => 0, 21676 ); 21677 if (!defined $tmpfile) { 21678 die M"Tempor�re Postscript-Datei kann nicht erstellt werden."; 21679 } 21680 } 21681 21682 if (!$post_processing_needed) { 21683 if (defined $tmpfile) { 21684 mv($tmpfile, $outfile); 21685 } 21686 } else { 21687 require GfxConvert; 21688 # -mapcolor wandelt die Farbe der Nebenstra�en 21689 # (tk: grey99/ps: 0.9 0.9 0.9) nach wei� um und setzt die 21690 # Hintergrundfarbe von wei� auf die Hintergrundfarbe des 21691 # Canvases 21692 GfxConvert::convert 21693 ($in_fmt, $fmt, $tmpfile, $outfile, 21694 %args, 21695 ); 21696 $tmpfiles{$tmpfile}++; 21697 } 21698 }; 21699 my $err = $@; 21700 DecBusy($top); 21701 $redisplay_toplevels->(); 21702 if ($err) { 21703 status_message($err, 'err'); 21704 } 21705} 21706 21707sub slow_postscript_generation { 21708 # XXX Hmmm, seems to be OK on Win98 with Tk800 and Tk804, with quite a number of layers turned on 21709 # XXX But it is really slow on a Windows2000 system with Tk800 (SiePerl 5.6.1) 21710 return $os eq 'win' && 21711 $top->messageBox(-icon => "question", 21712 -message => M"Die PostScript-Erzeugung k�nnte unter Windows langsam sein. Soll trotzdem fortgesetzt werden?", 21713 -type => "YesNo") !~ /yes/i; 21714} 21715 21716sub get_strassen_file { 21717 my $file = shift; 21718 if ($file =~ /-orig$/) { 21719 # XXX The need to check for this condition seems to be a bug. 21720 # In BBBikeLazy.pm, there are lines like 21721 # $p_file{$abk} = $file; 21722 # which set the $p_file{...} filename to the -orig version 21723 # in edit mode, and this every time! 21724 $file; 21725 } else { 21726 $file . ($edit_mode_flag ? "-orig" : ""); 21727 } 21728} 21729 21730sub get_strassen_obj { 21731 my $file = shift; 21732 my $object; 21733 if ($edit_mode_flag) { 21734 $object = eval { Strassen->new(get_strassen_file($file)) }; 21735 } 21736 if (!$object) { 21737 $object = Strassen->new($file); # fallback to non-orig file, if necessary 21738 } 21739 $object; 21740} 21741 21742sub get_any_strassen_obj { 21743 my($linetype, $type) = @_; 21744 my $object; 21745 if ($linetype =~ /^s/) { 21746 if ($type eq 'w') { 21747 $object = _get_wasser_obj(get_strassen_file($str_file{$type})); 21748 } elsif ($type eq 'l') { 21749 $object = _get_landstr_obj(); 21750 } elsif ($type eq 'comm') { 21751 $object = _get_comments_obj(); 21752 } elsif ($type eq 'fz') { 21753 $object = _get_fragezeichen_obj(); 21754 } else { 21755 $object = get_strassen_obj($str_file{$type}); 21756 } 21757 } else { 21758 $object = get_strassen_obj($p_file{$type}); 21759 } 21760 $object; 21761} 21762 21763sub handle_global_directives { 21764 my($s_or_file, $abk) = @_; 21765 my $glob_dir; 21766 if (!ref $s_or_file) { 21767 $glob_dir = Strassen->get_global_directives($s_or_file); 21768 } else { 21769 $glob_dir = $s_or_file->get_global_directives; 21770 } 21771 return if !$glob_dir; 21772 # XXX One day this should contain all of @plotting_hint_line_vars 21773 my %accept_modern_style = map{($_,1)} 21774 qw(line_arrow line_dash); 21775 # XXX Everything else should be slowly discouraged... 21776 my %accept_global_hash_directives = map{($_,1)} 21777 qw(category_size category_color 21778 category_line_width category_image 21779 category_stipple category_dash 21780 category_capstyle 21781 category_line_shorten category_line_shorten_end 21782 ); 21783 my %accept_global_hashref_directives = map{($_,1)} 21784 qw(str_attrib p_attrib); 21785 my %accept_global_catless_directives = map{($_,1)} 21786 qw(str_color outline_color line_width); 21787 my %accept_global_catless_directives_with_layer_prefix = map{($_,1)} 21788 qw(line_length 21789 line_dash line_arrow 21790 line_capstyle 21791 line_shorten line_shorten_end 21792 name 21793 ); 21794 # Aliases for directives without category 21795 my %aliases = ( 21796 category_width => "category_line_width", 21797 line_color => "str_color", 21798 ); 21799 # Aliases for directives with category 21800 my %aliases_withcat = ( 21801 line_color => "category_color", 21802 ); 21803 my @aliases_code = ( 21804 sub { $_[0] =~ s{^category_dash\.}{line_dash.}; }, # was used in radwege-orig, and is still used in streets-accurate-categorized..., remove some day XXX 21805 ); 21806 21807 my $get_val = sub { 21808 my($key, $vals) = @_; 21809 my $val = $vals->[0]; 21810 if ($key =~ m{(?:_dash|_capstyle|^line_length$)}) { # list of directives using arrays 21811 $val = [split /\s*,\s*/, $val]; 21812 } elsif ($key =~ m{_width}) { 21813 my @vals = split /\s*,\s*/, $val; 21814 if (@vals == 1) { 21815 my $factor = $vals[0] / $line_width{default}->[3]; 21816 for my $inx (0 .. $#{ $line_width{default} }) { 21817 $vals[$inx] = int($line_width{default}->[$inx] * $factor + 0.5); 21818 if ($vals[$inx] < 1) { 21819 $vals[$inx] = 1; 21820 } 21821 } 21822 } elsif (@vals != scalar @{ $line_width{default} }) { 21823 warn "$key should have either one or exactly six comma-separated values"; 21824 } 21825 $val = \@vals; 21826 } 21827 $val; 21828 }; 21829 21830 # XXX scrollregion 21831 while(my($directive, $vals) = each %$glob_dir) { 21832 if ($aliases{$directive}) { 21833 $directive = $aliases{$directive}; 21834 } 21835 for my $code (@aliases_code) { 21836 $code->($directive); 21837 } 21838 if ($accept_modern_style{$directive}) { 21839 no strict 'refs'; 21840 ${"layer_".$directive}{$abk} = $get_val->($directive, $vals); 21841 } elsif ($accept_global_catless_directives{$directive}) { 21842 no strict 'refs'; 21843 ${$directive}{$abk} = $get_val->($directive, $vals); 21844 } elsif ($accept_global_catless_directives_with_layer_prefix{$directive}) { 21845 no strict 'refs'; 21846 ${"layer_".$directive}{$abk} = $get_val->($directive, $vals); 21847 } elsif ($directive eq 'layer_stack') { 21848 my($how, $other_abk) = split /:/, $vals->[0]; 21849 if (!defined $other_abk) { 21850 status_message("The layer_stack directive needs how:tag as an argument", "die"); 21851 } 21852 set_in_stack($abk, $how, $other_abk); 21853 } else { 21854 my($key, $cat) = $directive =~ /^([^\.]+)\.([^\.]+)/; 21855 if (defined $key) { 21856 if ($aliases_withcat{$key}) { 21857 $key = $aliases_withcat{$key}; 21858 } 21859 if ($accept_modern_style{$key}) { 21860 no strict 'refs'; 21861 ${"layer_category_".$key}{$abk}{$cat} = $get_val->($key, $vals); 21862 next; 21863 } elsif ($accept_global_hash_directives{$key}) { 21864 no strict 'refs'; 21865 ${"layer_".$key}{$abk}{$cat} = $get_val->($key, $vals); 21866 next; 21867 } elsif ($accept_global_hashref_directives{$key}) { 21868 no strict 'refs'; 21869 ${$key}->{$abk."-".$cat} = $get_val->($key, $vals); # XXX $abk-??? 21870 next; 21871 } 21872 } 21873 #warn "Don't know how to handle global directive <$key>"; 21874 } 21875 } 21876} 21877 21878sub withdraw_tearoff_menus { 21879 my($toplevel) = @_; 21880 my @deiconify_subs; 21881 for my $w ($toplevel->children) { 21882 if (Tk::Exists($w) && $w->isa("Tk::Menu") && $w->state eq 'normal') { 21883 $w->withdraw; 21884 push @deiconify_subs, sub { $w->deiconify if Tk::Exists($w) }; 21885 } 21886 } 21887 @deiconify_subs; 21888} 21889 21890sub withdraw_toplevels { 21891 my $deiconify_subs = [ withdraw_tearoff_menus($top) ]; 21892 $top->Walk 21893 (sub { 21894 my($w) = @_; 21895 if (Tk::Exists($w) && $w->isa("Tk::Toplevel") && 21896 $w->state eq 'normal') { 21897 $w->withdraw; 21898 push @$deiconify_subs, sub { $w->deiconify if Tk::Exists($w) }; 21899 push @$deiconify_subs, withdraw_tearoff_menus($w); 21900 } 21901 }); 21902 $deiconify_subs; 21903} 21904 21905sub set_as_toolwindow { 21906 my($win, $parent) = @_; 21907 if ($transient) { 21908 if (0 && $Tk::platform eq 'MSWin32' && $Tk::VERSION >= 804) { 21909 # XXX using -topmost seems to be mandatory, but is ugly, 21910 # because the window is also topmost to other apps 21911 $win->attributes(-toolwindow => 1, -topmost => 1); 21912 } else { 21913 $parent = $top if !$parent; 21914 $win->transient($parent); 21915 } 21916 } 21917} 21918 21919sub get_image { 21920 my($base, $file) = @_; 21921 21922 my $images = ($top->{'MapImages'} ||= {}); 21923 my $p = $images->{$base}; 21924 if (!$p) { 21925 my $try_file = try_image_suffix($file); 21926 if (defined $try_file) { 21927 $file = $try_file; 21928 } 21929 eval { 21930 if ($file =~ /\.png$/ && !exists $INC{"Tk/PNG.pm"}) { 21931 require Tk::PNG; 21932 } 21933 if ($file =~ /\.jpe?g$/ && !exists $INC{"Tk/JPEG.pm"} && !exists $INC{"Tk/JPEG/Lite.pm"}) { 21934 require Tk::JPEG; # fallback to Tk::JPEG::Lite? XXX 21935 } 21936 21937 #warn "Try $file...\n"; 21938 $p = $c->Photo(-file => $file); 21939 }; 21940 if (!$p) { 21941 eval { 21942 my $try_file = try_image_suffix("$FindBin::RealBin/images/$file"); 21943 if (defined $try_file) { 21944 $file = $try_file; 21945 } else { 21946 warn "Could not find $file in images, try in \@INC..."; # XXX should never happen? 21947 $file = Tk::findINC($file); 21948 } 21949 #warn "Try $file...\n"; 21950 $p = $c->Photo(-file => $file) 21951 if defined $file; 21952 }; 21953 } 21954 if ($p) { 21955 $images->{$base} = $p; 21956 } 21957 } 21958 $p; 21959} 21960 21961sub get_image_for_p { 21962 my($base, $file, $abk) = @_; 21963 get_image_for_any($base, $file, $abk, 'p'); 21964} 21965 21966sub get_image_for_str { 21967 my($base, $file, $abk) = @_; 21968 get_image_for_any($base, $file, $abk, 'str'); 21969} 21970 21971sub get_image_for_any { 21972 my($base, $file, $abk, $type) = @_; 21973 21974 my($realfile,$w,$h,$refscale,$doxxx); 21975 my $is_svg; 21976 if ($file =~ m{(.*\.svg)(?::(\d+)x(\d+)(?:=1:(\d+)(,xxx)?)?)?$}) { 21977 ($realfile,$w,$h,$refscale,$doxxx) = ($1,$2,$3,$4,$5); 21978 $is_svg = 1; 21979 } else { 21980 $realfile = $file; 21981 } 21982 my $images = ($top->{'MapImages'} ||= {}); 21983 my $key = $base.' '.$realfile.' '.(defined $w ? $w.'x'.$h.' ' : '').(defined $refscale ? "$mapscale " : '').$type.' '.$abk; 21984 my $p = $images->{$key}; 21985 if (!$p) { 21986 eval { 21987 my $abs_realfile; 21988 if ($realfile =~ m{^/}) { 21989 $abs_realfile = $realfile; 21990 } else { 21991 # XXX Es ist nicht zugesichert, dass eine Datei f�r ein 21992 # p/str-Objekt existiert. Somit kann $p/str_file{$abk} 21993 # leer sein und der dirname-Aufruf meckern (fileparse() 21994 # need a valid pathname) 21995 my $bbd_abspath = $type eq 'p' ? $p_file{$abk} : $str_file{$abk}; 21996 if ($bbd_abspath !~ m{^/}) { # XXX windows compat? Should check for all occurences of this pattern and replace by function! 21997 $bbd_abspath = "$datadir/$bbd_abspath"; 21998 } 21999 my $dir = dirname($bbd_abspath); 22000 $abs_realfile = "$dir/$realfile"; 22001 } 22002 if ($is_svg) { 22003 # XXX move svg stuff to some general-purpose function or module 22004 if (!defined $w) { 22005 ($w,$h) = (100,100); # some hardcoded default 22006 } 22007 if (defined $refscale) { 22008 my($curr_mapscale) = $mapscale =~ m{^1:(\d+)}; # ignore decimals, if any 22009 my $factor = $refscale/$curr_mapscale; 22010 $factor = 0.5+$factor/2 if $doxxx; # XXX good name for xxx? make the factor "flatter" 22011 $w *= $factor; 22012 $h *= $factor; 22013 } 22014 $p = svg2photo($abs_realfile, $w, $h); 22015 } else { 22016 $p = get_image($base, $realfile); 22017 if (!$p) { 22018 warn "Try $abs_realfile...\n"; 22019 $p = $c->Photo(-file => $abs_realfile); 22020 } 22021 } 22022 }; 22023 if ($@) { 22024 warn "Warning: $@ (supplid args: ($base, $file, $abk, $type)" if $@; 22025 $p = $c->Photo(-file => "$FindBin::RealBin/images/px_1t.gif"); # XXX cache this one! 22026 } 22027 if ($p) { 22028 $images->{$key} = $p; 22029 } 22030 } 22031 $p; 22032} 22033 22034sub svg2photo { 22035 my($file, $w, $h) = @_; 22036 warn "Try to convert from svg to png, geometry ${w}x${h}...\n" if $verbose; 22037 require File::Temp; 22038 require Tk::PNG; 22039 my(undef,$tmpfile) = File::Temp::tempfile(SUFFIX => ".png", UNLINK => 1) 22040 or die "Can't create temporary file: $!"; 22041 my @cmd = ("convert", "-geometry", "${w}x${h}", $file, $tmpfile); 22042 system(@cmd) == 0 22043 or die "Error while converting: @cmd, status=$?"; 22044 my $p = $c->Photo(-file => $tmpfile); 22045 unlink $tmpfile; 22046 $p; 22047} 22048 22049sub pp_color { 22050 if (ref $pp_color eq 'ARRAY') { 22051 $c->itemconfigure('ppkvp', 22052 -fill => $pp_color->[0]); 22053## 2nd not yet used: 22054# $c->itemconfigure('ppcrs', 22055# -fill => $pp_color->[1]); 22056 $c->itemconfigure('ppcrs', 22057 -fill => $pp_color->[0]); 22058 } else { 22059 $c->itemconfigure('pp', 22060 -fill => $pp_color); 22061 } 22062} 22063 22064# Very nice. Note that the Tk::CanvasBalloon::Track method cannot cope with 22065# dealing with stacked items, so the <Motion> binding in std_str_binding 22066# needs additional code to deal with this. 22067sub balloon_info_from_all_tags { 22068 my($c) = @_; 22069 my $e = $c->XEvent; 22070 my($xx, $yy) = ($c->canvasx($e->x), $c->canvasy($e->y)); 22071 my $closeenough = $balloon_info_from_all_tags_closeenough; 22072 my(@items) = $c->find(overlapping => 22073 $xx-$closeenough, $yy-$closeenough, 22074 $xx+$closeenough, $yy+$closeenough); 22075 # Now using "reverse", so top-most items are preferred 22076 @items = reverse @items; 22077 if (!@items) { 22078 push @items, "current"; 22079 } 22080 my @major_balloon_info; 22081 my @balloon_info; 22082 my %balloon_info_seen; 22083 my $major_item_seen = 0; 22084 my $comments_rx = join("|", map { "comm-" . quotemeta } 22085 grep { $_ ne "kfzverkehr" } # list types without meaningful "name" field XXX but maybe comm-kfzverkehr should have meaningful names some day... 22086 @Strassen::Dataset::comments_types); 22087 22088 for my $item (@items) { 22089 my(@tags) = $c->gettags($item); 22090 if ($verbose && $verbose >= 2) { 22091 require Data::Dumper; 22092 print STDERR "Line " . __LINE__ . ", File: " . __FILE__ . "\n" . Data::Dumper->new([\@tags],[qw()])->Indent(1)->Useqq(1)->Dump; 22093 } 22094 22095 if ($tags[0] =~ m{^(s|sBAB|l|$comments_rx|qs|ql|hs|hl|fz|u|b|r|f|w|rw|e|v|v-fg|temp_sperre|temp_sperre_s|L\d+|L\d+-fg|L\d+-bg)$}) { 22096 my $label = $tags[1]; 22097 if ($tags[0] eq 'rw' || 22098 $tags[0] eq 'comm-cyclepath') { # Special handling for cyclepaths 22099 (my $rw_code) = $tags[2] =~ /^(?:rw|comm-cyclepath)-(RW(?:\d*|\?))/; # XXX should probably use $Radwege::rw_qr without the anchors? 22100 my $name = Radwege::code2name($rw_code); 22101 if (defined $name) { 22102 if (defined $label && $label ne "") { 22103 $label = "$name ($label)"; 22104 } else { 22105 $label = $name; 22106 } 22107 } 22108 } elsif ($tags[0] eq 'temp_sperre') { 22109 $label = $tags[2]; 22110 } 22111 next if $label =~ m{^\s*$}; 22112 $label =~ s/\|.*$//; # Teil hinter "|" abschneiden 22113 if ($tags[0] =~ m{^(s|l)$}) { # most significant, should be top-most: 22114 if (!exists $balloon_info_seen{$label}) { 22115 push @major_balloon_info, $label; 22116 $balloon_info_seen{$label} = 1; 22117 } 22118 $major_item_seen++; 22119 } else { 22120 if (($tags[2]||'') =~ m{^e-(CS|img)$}) { # comm-ferry 22121 if ($label =~ m{^(?:.*)?:\s*(.*)}) { 22122 $label = $1; 22123 } 22124 } elsif ($tags[0] =~ m{^(qs|ql|hs|hl)$}) { 22125 if ($label =~ m{^(?:.*)?:\s*(.*)}) { 22126 $label = $1; 22127 } 22128 if (my($cat) = $tags[2] =~ m{-(.*)}) { 22129 if ($cat eq 'img') { 22130 # not the category, but really an quality/handicap 22131 # image, most probably an in-construction image 22132 next; 22133 } 22134 $label .= " ($cat)"; 22135 } 22136 } elsif ($tags[0] =~ m{^L\d+-fg$}) { 22137 $label = $tags[2]; 22138 } 22139 if ($major_item_seen && $tags[0] =~ m{^(f|w)$}) { 22140 next; 22141 } 22142 if (!exists $balloon_info_seen{$label}) { 22143 push @balloon_info, $label; 22144 $balloon_info_seen{$label} = 1; 22145 } 22146 } 22147 } 22148 } 22149 22150 @balloon_info = (@major_balloon_info, @balloon_info); 22151 22152 if ($verbose && $verbose >= 2) { 22153 require Data::Dumper; 22154 print STDERR "Line " . __LINE__ . ", File: " . __FILE__ . "\n" . Data::Dumper->new([\@balloon_info],[qw(balloon_info)])->Indent(1)->Useqq(1)->Dump; 22155 } 22156 22157 if (wantarray) { 22158 if (!@balloon_info) { 22159 (); 22160 } else { 22161 @balloon_info; 22162 } 22163 } else { 22164 if (!@balloon_info) { 22165 undef; 22166 } else { 22167 join("\n", @balloon_info); 22168 } 22169 } 22170} 22171 22172sub get_special_vehicle { !defined $special_vehicle_rb || $special_vehicle_rb eq 'normal' ? '' : $special_vehicle_rb } 22173 22174# Currently works only if the original background is white 22175sub soft_flash { 22176 my $w = shift; 22177 # XXX Could be a little bit smoother... 22178 my @color_states = ('#ffe126', '#ffdb00', '#ffe126', '#ffe960', '#ffec74', '#fff19a', '#fff6be', '#ffffff'); 22179 my $color_i = 0; 22180 my $next_color_state; 22181 $next_color_state = sub { 22182 return if !Tk::Exists($w); 22183 $w->configure(-background => $color_states[$color_i]); 22184 $color_i++; 22185 if ($color_i <= $#color_states) { 22186 $w->after(100, $next_color_state); 22187 } 22188 }; 22189 $next_color_state->(); 22190} 22191 22192sub _can_send_mail { 22193 return $BBBikeMail::can_send_mail if defined $BBBikeMail::can_send_mail; 22194 22195 require BBBikeMail; 22196 BBBikeMail::capabilities(); 22197 $BBBikeMail::can_send_mail; 22198} 22199 22200# REPO BEGIN 22201# REPO NAME tk_sleep /home/e/eserte/work/srezic-repository 22202# REPO MD5 6e344458a3a154eefaf7b82d5f9bb576 22203 22204=head2 tk_sleep 22205 22206=for category Tk 22207 22208 $top->tk_sleep($s); 22209 22210Sleep $s seconds (fractions are allowed). Use this method in Tk 22211programs rather than the blocking sleep function. The difference to 22212$top->after($s/1000) is that refrsh events are still handled in the 22213sleeping time. 22214 22215=cut 22216 22217sub Tk::Widget::tk_sleep { 22218 my($top, $s) = @_; 22219 my $sleep_dummy = 0; 22220 $top->after($s*1000, 22221 sub { $sleep_dummy++ }); 22222 $top->waitVariable(\$sleep_dummy) 22223 unless $sleep_dummy; 22224} 22225# REPO END 22226 22227## DEBUG_BEGIN 22228#BEGIN{mymstat("100% BEGIN");} 22229## DEBUG_END 22230 22231package bbbike; # HACK for autosplit 22232