1 /*
2 * Dialog window for defining a schedule
3 *
4 * Hj. Malthaner
5 *
6 * Juli 2000
7 */
8
9 #include "../simline.h"
10 #include "../simcolor.h"
11 #include "../simhalt.h"
12 #include "../simworld.h"
13 #include "../simmenu.h"
14 #include "../simconvoi.h"
15 #include "../display/simgraph.h"
16 #include "../display/viewport.h"
17
18 #include "../utils/simstring.h"
19 #include "../utils/cbuffer_t.h"
20
21 #include "../boden/grund.h"
22
23 #include "../obj/zeiger.h"
24
25 #include "../dataobj/schedule.h"
26 #include "../dataobj/loadsave.h"
27 #include "../dataobj/translator.h"
28 #include "../dataobj/environment.h"
29
30 #include "../player/simplay.h"
31
32 #include "../tpl/vector_tpl.h"
33
34 #include "depot_frame.h"
35 #include "schedule_gui.h"
36 #include "line_item.h"
37
38 #include "components/gui_button.h"
39 #include "components/gui_image.h"
40 #include "components/gui_textarea.h"
41 #include "minimap.h"
42
43 static karte_ptr_t welt;
44
45 /**
46 * One entry in the list of schedule entries.
47 */
48 class gui_schedule_entry_t : public gui_aligned_container_t, public gui_action_creator_t
49 {
50 schedule_entry_t entry;
51 bool is_current;
52 uint number;
53 player_t* player;
54 gui_image_t arrow;
55 gui_label_buf_t stop;
56
57 public:
gui_schedule_entry_t(player_t * pl,schedule_entry_t e,uint n)58 gui_schedule_entry_t(player_t* pl, schedule_entry_t e, uint n)
59 {
60 player = pl;
61 entry = e;
62 number = n;
63 is_current = false;
64 set_table_layout(2,1);
65
66 add_component(&arrow);
67 arrow.set_image(gui_theme_t::pos_button_img[0], true);
68
69 add_component(&stop);
70 update_label();
71 }
72
update_label()73 void update_label()
74 {
75 stop.buf().printf("%i) ", number+1);
76 schedule_t::gimme_stop_name(stop.buf(), welt, player, entry, -1);
77 stop.update();
78 }
79
draw(scr_coord offset)80 void draw(scr_coord offset) OVERRIDE
81 {
82 update_label();
83 if (is_current) {
84 display_fillbox_wh_clip_rgb(pos.x + offset.x, pos.y + offset.y, size.w, size.h, SYSCOL_LIST_BACKGROUND_SELECTED_F, false);
85 }
86 gui_aligned_container_t::draw(offset);
87 }
88
set_active(bool yesno)89 void set_active(bool yesno)
90 {
91 is_current = yesno;
92 arrow.set_image(gui_theme_t::pos_button_img[yesno ? 1: 0], true);
93 stop.set_color(yesno ? SYSCOL_TEXT_HIGHLIGHT : SYSCOL_TEXT);
94 }
95
infowin_event(const event_t * ev)96 bool infowin_event(const event_t *ev) OVERRIDE
97 {
98 if( ev->ev_class == EVENT_CLICK ) {
99 if( IS_RIGHTCLICK(ev) || ev->mx < stop.get_pos().x) {
100 // just center on it
101 welt->get_viewport()->change_world_position( entry.pos );
102 }
103 else {
104 call_listeners(number);
105 }
106 return true;
107 }
108 return false;
109 }
110 };
111
112 /**
113 * List of displayed schedule entries.
114 */
115 class schedule_gui_stats_t : public gui_aligned_container_t, action_listener_t, public gui_action_creator_t
116 {
117 static cbuffer_t buf;
118
119 vector_tpl<gui_schedule_entry_t*> entries;
120 schedule_t *last_schedule; ///< last displayed schedule
121 zeiger_t *current_stop_mark; ///< mark current stop on map
122 public:
123 schedule_t *schedule; ///< schedule under editing
124 player_t* player;
125
schedule_gui_stats_t()126 schedule_gui_stats_t()
127 {
128 set_table_layout(1,0);
129 last_schedule = NULL;
130
131 current_stop_mark = new zeiger_t(koord3d::invalid, NULL );
132 current_stop_mark->set_image( tool_t::general_tool[TOOL_SCHEDULE_ADD]->cursor );
133 }
~schedule_gui_stats_t()134 ~schedule_gui_stats_t()
135 {
136 delete current_stop_mark;
137 delete last_schedule;
138 }
139
140 // shows/deletes highlighting of tiles
highlight_schedule(bool marking)141 void highlight_schedule(bool marking)
142 {
143 marking &= env_t::visualize_schedule;
144 FOR(minivec_tpl<schedule_entry_t>, const& i, schedule->entries) {
145 if (grund_t* const gr = welt->lookup(i.pos)) {
146 for( uint idx=0; idx<gr->get_top(); idx++ ) {
147 obj_t *obj = gr->obj_bei(idx);
148 if( marking ) {
149 if( !obj->is_moving() ) {
150 obj->set_flag( obj_t::highlight );
151 }
152 }
153 else {
154 obj->clear_flag( obj_t::highlight );
155 }
156 }
157 gr->set_flag( grund_t::dirty );
158 // here on water
159 if( gr->is_water() || gr->ist_natur() ) {
160 if( marking ) {
161 gr->set_flag( grund_t::marked );
162 }
163 else {
164 gr->clear_flag( grund_t::marked );
165 }
166 }
167
168 }
169 }
170 // always remove
171 if( grund_t *old_gr = welt->lookup(current_stop_mark->get_pos()) ) {
172 current_stop_mark->mark_image_dirty( current_stop_mark->get_image(), 0 );
173 old_gr->obj_remove( current_stop_mark );
174 old_gr->set_flag( grund_t::dirty );
175 current_stop_mark->set_pos( koord3d::invalid );
176 }
177 // add if required
178 if( marking && schedule->get_current_stop() < schedule->get_count() ) {
179 current_stop_mark->set_pos( schedule->entries[schedule->get_current_stop()].pos );
180 if( grund_t *gr = welt->lookup(current_stop_mark->get_pos()) ) {
181 gr->obj_add( current_stop_mark );
182 current_stop_mark->set_flag( obj_t::dirty );
183 gr->set_flag( grund_t::dirty );
184 }
185 }
186 current_stop_mark->clear_flag( obj_t::highlight );
187 }
188
update_schedule()189 void update_schedule()
190 {
191 // compare schedules
192 bool ok = (last_schedule != NULL) && last_schedule->entries.get_count() == schedule->entries.get_count();
193 for(uint i=0; ok && i<last_schedule->entries.get_count(); i++) {
194 ok = last_schedule->entries[i] == schedule->entries[i];
195 }
196 if (ok) {
197 if (!last_schedule->empty()) {
198 entries[ last_schedule->get_current_stop() ]->set_active(false);
199 entries[ schedule->get_current_stop() ]->set_active(true);
200 last_schedule->set_current_stop( schedule->get_current_stop() );
201 }
202 }
203 else {
204 remove_all();
205 entries.clear();
206 buf.clear();
207 buf.append(translator::translate("Please click on the map to add\nwaypoints or stops to this\nschedule."));
208 if (schedule->empty()) {
209 new_component<gui_textarea_t>(&buf);
210 }
211 else {
212 for(uint i=0; i<schedule->entries.get_count(); i++) {
213 entries.append( new_component<gui_schedule_entry_t>(player, schedule->entries[i], i));
214 entries.back()->add_listener( this );
215 }
216 entries[ schedule->get_current_stop() ]->set_active(true);
217 }
218 if (last_schedule) {
219 last_schedule->copy_from(schedule);
220 }
221 else {
222 last_schedule = schedule->copy();
223 }
224 set_size(get_min_size());
225 }
226 highlight_schedule(true);
227 }
draw(scr_coord offset)228 void draw(scr_coord offset) OVERRIDE
229 {
230 update_schedule();
231
232 gui_aligned_container_t::draw(offset);
233 }
action_triggered(gui_action_creator_t *,value_t v)234 bool action_triggered(gui_action_creator_t *, value_t v) OVERRIDE
235 {
236 // has to be one of the entries
237 call_listeners(v);
238 return true;
239 }
240 };
241
242 /**
243 * Entries in the waiting-time selection.
244 */
245 class gui_waiting_time_item_t : public gui_scrolled_list_t::const_text_scrollitem_t
246 {
247 private:
248 cbuffer_t buf;
249 sint8 wait;
250
251 public:
gui_waiting_time_item_t(sint8 w)252 gui_waiting_time_item_t(sint8 w) : gui_scrolled_list_t::const_text_scrollitem_t(NULL, SYSCOL_TEXT)
253 {
254 wait = w;
255 if (wait == 0) {
256 buf.append(translator::translate("off"));
257 }
258 else {
259 buf.printf("1/%d", 1<<(16 - wait) );
260 }
261 }
262
get_text() const263 char const* get_text () const OVERRIDE { return buf; }
264
get_wait_shift() const265 sint8 get_wait_shift() const { return wait; }
266 };
267
268 cbuffer_t schedule_gui_stats_t::buf;
269
schedule_gui_t(schedule_t * schedule_,player_t * player_,convoihandle_t cnv_)270 schedule_gui_t::schedule_gui_t(schedule_t* schedule_, player_t* player_, convoihandle_t cnv_) :
271 gui_frame_t( translator::translate("Fahrplan"), NULL),
272 line_selector(line_scrollitem_t::compare),
273 lb_waitlevel(SYSCOL_TEXT_HIGHLIGHT, gui_label_t::right),
274 lb_wait("month wait time"),
275 lb_load("Full load"),
276 stats(new schedule_gui_stats_t() ),
277 scrolly(stats)
278 {
279 schedule = NULL;
280 player = NULL;
281 if (schedule_) {
282 init(schedule_, player_, cnv_);
283 }
284 }
285
~schedule_gui_t()286 schedule_gui_t::~schedule_gui_t()
287 {
288 if( player ) {
289 update_tool( false );
290 // hide schedule on minimap (may not current, but for safe)
291 minimap_t::get_instance()->set_selected_cnv( convoihandle_t() );
292 }
293 delete schedule;
294 delete stats;
295 }
296
init(schedule_t * schedule_,player_t * player,convoihandle_t cnv)297 void schedule_gui_t::init(schedule_t* schedule_, player_t* player, convoihandle_t cnv)
298 {
299 // initialization
300 this->old_schedule = schedule_;
301 this->cnv = cnv;
302 this->player = player;
303 set_owner(player);
304
305 // prepare editing
306 old_schedule->start_editing();
307 schedule = old_schedule->copy();
308 if( !cnv.is_bound() ) {
309 old_line = new_line = linehandle_t();
310 }
311 else {
312 // set this schedule as current to show on minimap if possible
313 minimap_t::get_instance()->set_selected_cnv( cnv );
314 old_line = new_line = cnv->get_line();
315 }
316 old_line_count = 0;
317
318 stats->player = player;
319 stats->schedule = schedule;
320 stats->update_schedule();
321 stats->add_listener(this);
322
323 set_table_layout(1,0);
324
325 if( cnv.is_bound() ) {
326 add_table(3,1);
327 // things, only relevant to convois, like creating/selecting lines
328 new_component<gui_label_t>("Serves Line:");
329 bt_promote_to_line.init( button_t::roundbox, "promote to line");
330 bt_promote_to_line.set_tooltip("Create a new line based on this schedule");
331 bt_promote_to_line.add_listener(this);
332 new_component<gui_fill_t>();
333 add_component(&bt_promote_to_line);
334 end_table();
335
336 line_selector.clear_elements();
337
338 init_line_selector();
339 line_selector.add_listener(this);
340 add_component(&line_selector);
341 }
342
343 // loading level and waiting time
344 add_table(2,2);
345 {
346 add_component(&lb_load);
347
348 numimp_load.set_width( 60 );
349 numimp_load.set_value( schedule->get_current_entry().minimum_loading );
350 numimp_load.set_limits( 0, 100 );
351 numimp_load.set_increment_mode( gui_numberinput_t::PROGRESS );
352 numimp_load.add_listener(this);
353 add_component(&numimp_load);
354
355 add_component(&lb_wait);
356
357 add_component(&wait_load);
358 wait_load.add_listener(this);
359
360 wait_load.new_component<gui_waiting_time_item_t>(0);
361 for(sint8 w = 7; w<=16; w++) {
362 wait_load.new_component<gui_waiting_time_item_t>(w);
363 }
364 wait_load.set_rigid(true);
365 }
366 end_table();
367
368 // return tickets
369 if( !env_t::hide_rail_return_ticket || schedule->get_waytype()==road_wt || schedule->get_waytype()==air_wt || schedule->get_waytype()==water_wt ) {
370 // hide the return ticket on rail stuff, where it causes much trouble
371 bt_return.init(button_t::roundbox, "return ticket");
372 bt_return.set_tooltip("Add stops for backward travel");
373 bt_return.add_listener(this);
374 add_component(&bt_return);
375 }
376
377 // action button row
378 add_table(3,1)->set_force_equal_columns(true);
379 bt_add.init(button_t::roundbox_state | button_t::flexible, "Add Stop");
380 bt_add.set_tooltip("Appends stops at the end of the schedule");
381 bt_add.add_listener(this);
382 bt_add.pressed = true;
383 add_component(&bt_add);
384
385 bt_insert.init(button_t::roundbox_state | button_t::flexible, "Ins Stop");
386 bt_insert.set_tooltip("Insert stop before the current stop");
387 bt_insert.add_listener(this);
388 bt_insert.pressed = false;
389 add_component(&bt_insert);
390
391 bt_remove.init(button_t::roundbox_state | button_t::flexible, "Del Stop");
392 bt_remove.set_tooltip("Delete the current stop");
393 bt_remove.add_listener(this);
394 bt_remove.pressed = false;
395 add_component(&bt_remove);
396 end_table();
397
398 scrolly.set_show_scroll_x(true);
399 scrolly.set_scroll_amount_y(LINESPACE+1);
400 add_component(&scrolly);
401
402 mode = adding;
403 update_selection();
404
405 set_resizemode(diagonal_resize);
406
407 reset_min_windowsize();
408 set_windowsize(get_min_windowsize());
409 }
410
411
update_tool(bool set)412 void schedule_gui_t::update_tool(bool set)
413 {
414 if(!set || mode==removing || mode==undefined_mode) {
415 // reset tools, if still selected ...
416 if(welt->get_tool(player->get_player_nr())==tool_t::general_tool[TOOL_SCHEDULE_ADD]) {
417 if(tool_t::general_tool[TOOL_SCHEDULE_ADD]->get_default_param()==(const char *)schedule) {
418 welt->set_tool( tool_t::general_tool[TOOL_QUERY], player );
419 }
420 }
421 else if(welt->get_tool(player->get_player_nr())==tool_t::general_tool[TOOL_SCHEDULE_INS]) {
422 if(tool_t::general_tool[TOOL_SCHEDULE_INS]->get_default_param()==(const char *)schedule) {
423 welt->set_tool( tool_t::general_tool[TOOL_QUERY], player );
424 }
425 }
426 }
427 else {
428 // .. or set them again
429 if(mode==adding) {
430 tool_t::general_tool[TOOL_SCHEDULE_ADD]->set_default_param((const char *)schedule);
431 welt->set_tool( tool_t::general_tool[TOOL_SCHEDULE_ADD], player );
432 }
433 else if(mode==inserting) {
434 tool_t::general_tool[TOOL_SCHEDULE_INS]->set_default_param((const char *)schedule);
435 welt->set_tool( tool_t::general_tool[TOOL_SCHEDULE_INS], player );
436 }
437 }
438 }
439
440
update_selection()441 void schedule_gui_t::update_selection()
442 {
443 lb_wait.set_color( SYSCOL_BUTTON_TEXT_DISABLED );
444 wait_load.disable();
445
446 if( !schedule->empty() ) {
447 schedule->set_current_stop( min(schedule->get_count()-1,schedule->get_current_stop()) );
448 const uint8 current_stop = schedule->get_current_stop();
449 if( haltestelle_t::get_halt(schedule->entries[current_stop].pos, player).is_bound() ) {
450 lb_load.set_color( SYSCOL_TEXT );
451 numimp_load.enable();
452 numimp_load.set_value( schedule->entries[current_stop].minimum_loading );
453
454 sint8 wait = 0;
455 if( schedule->entries[current_stop].minimum_loading>0 ) {
456 lb_wait.set_color( SYSCOL_TEXT );
457 wait_load.enable();
458
459 wait = schedule->entries[current_stop].waiting_time_shift;
460 }
461
462 for(int i=0; i<wait_load.count_elements(); i++) {
463 if (gui_waiting_time_item_t *item = dynamic_cast<gui_waiting_time_item_t*>( wait_load.get_element(i) ) ) {
464 if (item->get_wait_shift() == wait) {
465 wait_load.set_selection(i);
466 break;
467 }
468 }
469 }
470
471 }
472 else {
473 lb_load.set_color( SYSCOL_BUTTON_TEXT_DISABLED );
474 numimp_load.disable();
475 numimp_load.set_value( 0 );
476 }
477 }
478 }
479
480
481 /**
482 * Mouse clicks are hereby reported to its GUI-Components
483 */
infowin_event(const event_t * ev)484 bool schedule_gui_t::infowin_event(const event_t *ev)
485 {
486 if( (ev)->ev_class == EVENT_CLICK && !((ev)->ev_code==MOUSE_WHEELUP || (ev)->ev_code==MOUSE_WHEELDOWN) && !line_selector.getroffen(ev->cx, ev->cy-D_TITLEBAR_HEIGHT) ) {
487
488 // close combo box; we must do it ourselves, since the box does not receive outside events ...
489 line_selector.close_box();
490 }
491 else if( ev->ev_class == INFOWIN && ev->ev_code == WIN_CLOSE && schedule!=NULL ) {
492
493 stats->highlight_schedule( false );
494
495 update_tool( false );
496 schedule->cleanup();
497 schedule->finish_editing();
498 // now apply the changes
499 if( cnv.is_bound() ) {
500 // do not send changes if the convoi is about to be deleted
501 if( cnv->get_state() != convoi_t::SELF_DESTRUCT ) {
502 // if a line is selected
503 if( new_line.is_bound() ) {
504 // if the selected line is different to the convoi's line, apply it
505 if( new_line!=cnv->get_line() ) {
506 char id[16];
507 sprintf( id, "%i,%i", new_line.get_id(), schedule->get_current_stop() );
508 cnv->call_convoi_tool( 'l', id );
509 }
510 else {
511 cbuffer_t buf;
512 schedule->sprintf_schedule( buf );
513 cnv->call_convoi_tool( 'g', buf );
514 }
515 }
516 else {
517 cbuffer_t buf;
518 schedule->sprintf_schedule( buf );
519 cnv->call_convoi_tool( 'g', buf );
520 }
521
522 if( cnv->in_depot() ) {
523 const grund_t *const ground = welt->lookup( cnv->get_home_depot() );
524 if( ground ) {
525 const depot_t *const depot = ground->get_depot();
526 if( depot ) {
527 depot_frame_t *const frame = dynamic_cast<depot_frame_t *>( win_get_magic( (ptrdiff_t)depot ) );
528 if( frame ) {
529 frame->update_data();
530 }
531 }
532 }
533 }
534 }
535 }
536 }
537 else if( ev->ev_class == INFOWIN && (ev->ev_code == WIN_TOP || ev->ev_code == WIN_OPEN) && schedule!=NULL ) {
538 // just to be sure, renew the tools ...
539 update_tool( true );
540 }
541
542 return gui_frame_t::infowin_event(ev);
543 }
544
545
action_triggered(gui_action_creator_t * comp,value_t p)546 bool schedule_gui_t::action_triggered( gui_action_creator_t *comp, value_t p)
547 {
548 DBG_MESSAGE("schedule_gui_t::action_triggered()","comp=%p combo=%p",comp,&line_selector);
549
550 if(comp == &bt_add) {
551 mode = adding;
552 bt_add.pressed = true;
553 bt_insert.pressed = false;
554 bt_remove.pressed = false;
555 update_tool( true );
556 }
557 else if(comp == &bt_insert) {
558 mode = inserting;
559 bt_add.pressed = false;
560 bt_insert.pressed = true;
561 bt_remove.pressed = false;
562 update_tool( true );
563 }
564 else if(comp == &bt_remove) {
565 mode = removing;
566 bt_add.pressed = false;
567 bt_insert.pressed = false;
568 bt_remove.pressed = true;
569 update_tool( false );
570 }
571 else if(comp == &numimp_load) {
572 if (!schedule->empty()) {
573 schedule->entries[schedule->get_current_stop()].minimum_loading = (uint8)p.i;
574 update_selection();
575 }
576 }
577 else if(comp == &wait_load) {
578 if(!schedule->empty()) {
579 if (gui_waiting_time_item_t *item = dynamic_cast<gui_waiting_time_item_t*>( wait_load.get_selected_item())) {
580 schedule->entries[schedule->get_current_stop()].waiting_time_shift = item->get_wait_shift();
581
582 update_selection();
583 }
584 }
585 }
586 else if(comp == &bt_return) {
587 schedule->add_return_way();
588 }
589 else if(comp == &line_selector) {
590 uint32 selection = p.i;
591 if( line_scrollitem_t *li = dynamic_cast<line_scrollitem_t*>(line_selector.get_element(selection)) ) {
592 new_line = li->get_line();
593 stats->highlight_schedule( false );
594 schedule->copy_from( new_line->get_schedule() );
595 schedule->start_editing();
596 }
597 else {
598 // remove line
599 new_line = linehandle_t();
600 line_selector.set_selection( 0 );
601 }
602 }
603 else if(comp == &bt_promote_to_line) {
604 // update line schedule via tool!
605 tool_t *tool = create_tool( TOOL_CHANGE_LINE | SIMPLE_TOOL );
606 cbuffer_t buf;
607 buf.printf( "c,0,%i,%ld,", (int)schedule->get_type(), (long)old_schedule );
608 schedule->sprintf_schedule( buf );
609 tool->set_default_param(buf);
610 welt->set_tool( tool, player );
611 // since init always returns false, it is safe to delete immediately
612 delete tool;
613 }
614 else if (comp == stats) {
615 // click on one of the schedule entries
616 const int line = p.i;
617
618 if( line >= 0 && line < schedule->get_count() ) {
619 schedule->set_current_stop( line );
620 if( mode == removing ) {
621 stats->highlight_schedule( false );
622 schedule->remove();
623 action_triggered( &bt_add, value_t() );
624 }
625 update_selection();
626 }
627 }
628 // recheck lines
629 if( cnv.is_bound() ) {
630 // unequal to line => remove from line ...
631 if( new_line.is_bound() && !schedule->matches(welt,new_line->get_schedule()) ) {
632 new_line = linehandle_t();
633 line_selector.set_selection(0);
634 }
635 // only assign old line, when new_line is not equal
636 if( !new_line.is_bound() && old_line.is_bound() && schedule->matches(welt,old_line->get_schedule()) ) {
637 new_line = old_line;
638 init_line_selector();
639 }
640 }
641 return true;
642 }
643
644
init_line_selector()645 void schedule_gui_t::init_line_selector()
646 {
647 line_selector.clear_elements();
648 int selection = 0;
649 vector_tpl<linehandle_t> lines;
650
651 player->simlinemgmt.get_lines(schedule->get_type(), &lines);
652
653 // keep assignment with identical schedules
654 if( new_line.is_bound() && !schedule->matches( welt, new_line->get_schedule() ) ) {
655 if( old_line.is_bound() && schedule->matches( welt, old_line->get_schedule() ) ) {
656 new_line = old_line;
657 }
658 else {
659 new_line = linehandle_t();
660 }
661 }
662 int offset = 0;
663 if( !new_line.is_bound() ) {
664 selection = 0;
665 offset = 1;
666 line_selector.new_component<gui_scrolled_list_t::const_text_scrollitem_t>( translator::translate("<no line>"), SYSCOL_TEXT ) ;
667 }
668
669 FOR( vector_tpl<linehandle_t>, line, lines ) {
670 line_selector.new_component<line_scrollitem_t>(line) ;
671 if( !new_line.is_bound() ) {
672 if( schedule->matches( welt, line->get_schedule() ) ) {
673 selection = line_selector.count_elements()-1;
674 new_line = line;
675 }
676 }
677 else if( new_line == line ) {
678 selection = line_selector.count_elements()-1;
679 }
680 }
681
682 line_selector.set_selection( selection );
683 line_scrollitem_t::sort_mode = line_scrollitem_t::SORT_BY_NAME;
684 line_selector.sort( offset );
685 old_line_count = player->simlinemgmt.get_line_count();
686 last_schedule_count = schedule->get_count();
687 }
688
689
690
draw(scr_coord pos,scr_size size)691 void schedule_gui_t::draw(scr_coord pos, scr_size size)
692 {
693 if( player->simlinemgmt.get_line_count()!=old_line_count || last_schedule_count!=schedule->get_count() ) {
694 // lines added or deleted
695 init_line_selector();
696 last_schedule_count = schedule->get_count();
697 }
698
699 // after loading in network games, the schedule might still being updated
700 if( cnv.is_bound() && cnv->get_state()==convoi_t::EDIT_SCHEDULE && schedule->is_editing_finished() ) {
701 assert( convoi_t::EDIT_SCHEDULE==1 ); // convoi_t::EDIT_SCHEDULE is 1
702 schedule->start_editing();
703 cnv->call_convoi_tool( 's', "1" );
704 }
705
706 // always dirty, to cater for shortening of halt names and change of selections
707 set_dirty();
708 gui_frame_t::draw(pos,size);
709 }
710
711
712 /**
713 * Set window size and adjust component sizes and/or positions accordingly
714 * @author Hj. Malthaner
715 * @date 16-Oct-2003
716 */
set_windowsize(scr_size size)717 void schedule_gui_t::set_windowsize(scr_size size)
718 {
719 gui_frame_t::set_windowsize(size);
720 // manually enlarge size of wait_load combobox
721 wait_load.set_size( scr_size(numimp_load.get_size().w, wait_load.get_size().h) );
722 // make scrolly take all of space
723 scrolly.set_size( scr_size(scrolly.get_size().w, get_client_windowsize().h - scrolly.get_pos().y - D_MARGIN_BOTTOM));
724
725 }
726
727
map_rotate90(sint16 y_size)728 void schedule_gui_t::map_rotate90( sint16 y_size)
729 {
730 schedule->rotate90(y_size);
731 }
732
733
rdwr(loadsave_t * file)734 void schedule_gui_t::rdwr(loadsave_t *file)
735 {
736 // this handles only schedules of bound convois
737 // lines are handled by line_management_gui_t
738
739 // window size
740 scr_size size = get_windowsize();
741 size.rdwr( file );
742
743 // convoy data
744 convoi_t::rdwr_convoihandle_t(file, cnv);
745
746 // save edited schedule
747 if( file->is_loading() ) {
748 // dummy types
749 schedule = new truck_schedule_t();
750 }
751 schedule->rdwr(file);
752
753 if( file->is_loading() ) {
754 if( cnv.is_bound() ) {
755
756 schedule_t *save_schedule = schedule->copy();
757
758 init(cnv->get_schedule(), cnv->get_owner(), cnv);
759 // init replaced schedule, restore
760 schedule->copy_from(save_schedule);
761 delete save_schedule;
762
763 set_windowsize(size);
764
765 // draw will init editing phase again, has to be synchronized
766 cnv->get_schedule()->finish_editing();
767 schedule->finish_editing();
768
769 win_set_magic(this, (ptrdiff_t)cnv->get_schedule());
770 }
771 else {
772 player = NULL; // prevent destructor from updating
773 destroy_win( this );
774 dbg->error( "schedule_gui_t::rdwr", "Could not restore schedule window for (%d)", cnv.get_id() );
775 }
776 }
777 }
778