/**********************************************************************
This file is part of Crack dot Com's free source code release of
Golgotha.
for
information about compiling & licensing issues visit this URL
If that doesn't help, contact Jonathan Clark at
golgotha_source@usa.net (Subject should have "GOLG" in it)
***********************************************************************/
#include "window/window.hh"
#include "window/style.hh"
#include "gui/button.hh"
#include "editor/dialogs/e_time.hh"
#include "window/win_evt.hh"
#include "gui/image_win.hh"
#include "gui/button.hh"
#include "device/keys.hh"
#include "gui/text_input.hh"
#include "gui/deco_win.hh"
#include "gui/text.hh"
#include "math/num_type.hh"
#include "editor/e_state.hh"
#include "math/spline.hh"
#include "m_flow.hh"
#include "editor/editor.hh"
#include "editor/e_state.hh"
#include "loaders/load.hh"
#include "gui/butbox.hh"
#include "g1_speed.hh"
#include "mess_id.hh"
#include "app/app.hh"
#include "editor/e_res.hh"
class g1_time_show : public i4_window_class
{
i4_graphical_style_class *style;
i4_event_handler_reference_class tl;
public:
g1_time_show(i4_graphical_style_class *style,
g1_time_line *tl)
: i4_window_class(style->font_hint->normal_font->largest_width()*6,
style->font_hint->normal_font->largest_height()),
style(style)
{
tl=tl;
}
void draw(i4_draw_context_class &context)
{
style->deco_neutral_fill(local_image, 0,0, width()-1, height()-1, context);
if (!tl.get()) return;
i4_font_class *f=style->font_hint->normal_font;
f->set_color(style->color_hint->text_foreground);
i4_float t=tl->current_frame()/(i4_float)(G1_MOVIE_HZ);
sw32 sec=(sw32)t;
sw32 msec=(sw32)((t-sec)*100);
i4_str *out=g1_editor_instance.get_editor_string("time_format").sprintf(20, sec, msec);
f->put_string(local_image, 0,0, *out, context);
delete out;
}
char *name() { return "time show"; }
};
class g1_frame_show : public i4_text_input_class
{
i4_event_handler_reference_class tl;
public:
g1_frame_show(i4_graphical_style_class *style,
g1_time_line *tl)
: i4_text_input_class(style,
g1_editor_instance.get_editor_string("0"),
50,
8)
{
tl=tl;
}
virtual void become_unactive()
{
i4_const_str::iterator i=st->begin();
w32 v=i.read_number();
i4_text_input_class::become_unactive();
}
void receive_event(i4_event *ev)
{
if (!tl.get()) return;
CAST_PTR(kev, i4_key_press_event_class, ev);
if (ev->type()==i4_event::KEY_PRESS && kev->key==I4_ENTER)
{
become_unactive();
i4_const_str::iterator i=st->begin();
sw32 x=i.read_number();
if (tl->selected_spline() && x>0)
{
g1_editor_instance.add_undo(G1_MAP_MOVIE);
i4_spline_class::point *p;
w32 frame=tl->current_frame();
p=tl->selected_spline()->get_control_point_previous_to_frame(frame);
sw32 add=x-(p->next->frame-p->frame);
p=p->next;
for (;p;p=p->next)
p->frame+=add;
g1_editor_instance.changed();
}
}
else i4_text_input_class::receive_event(ev);
}
void update()
{
i4_str *st;
if (!tl.get()) return;
if (tl->selected_spline())
{
i4_spline_class::point *p;
w32 frame=tl->current_frame();
p=tl->selected_spline()->get_control_point_previous_to_frame(frame);
if (p && p->next)
st=g1_editor_instance.get_editor_string("frame_format").sprintf(20,
p->next->frame-p->frame);
else
st=new i4_str(g1_editor_instance.get_editor_string("no_next"));
}
else
st=new i4_str(g1_editor_instance.get_editor_string("not_sel"));
change_text(*st);
delete st;
}
char *name() { return "time show"; }
};
class g1_time_scroller : public i4_parent_window_class
{
i4_event_handler_reference_class tl;
i4_graphical_style_class *style;
sw32 mx,my;
i4_bool mouse_down;
public:
char *name() { return "time sroller"; }
g1_time_scroller(w16 w, w16 h,
i4_graphical_style_class *style,
g1_time_line *tl)
: i4_parent_window_class(w,h),
style(style)
{
tl=tl;
mouse_down=i4_F;
}
void parent_draw(i4_draw_context_class &context)
{
style->draw_in_deco(local_image, 0,0, width()-1, height()-1, i4_F, context);
w32 l,r,t,b;
style->get_in_deco_size(l,r,t,b);
local_image->bar(l,r,width()-r,height()-t, style->color_hint->window.active.medium, context);
local_image->line(l,height()/2,width()-r, height()/2, 0xffffffff, context);
if (!tl.get()) return;
int tf=tl->total_frames();
if (tf)
{
w32 o=tl->current_frame()*(width()-l-r)/tf+l;
local_image->line(o,t,o,height()-b, 0xffffffff, context);
}
}
void mouse_change_time()
{
if (!tl.get()) return;
w32 l,r,t,b;
style->get_in_deco_size(l,r,t,b);
if (mx>=width()-r)
tl->set_current(tl->total_frames()-1, i4_T);
else if (mxset_current(0, i4_T);
else
tl->set_current( (mx-l)*tl->total_frames()/(width()-l-r), i4_T);
request_redraw();
}
void g1_time_scroller::receive_event(i4_event *ev)
{
switch (ev->type())
{
case i4_event::MOUSE_MOVE :
{
CAST_PTR(mev, i4_mouse_move_event_class, ev);
mx=mev->x;
my=mev->y;
if (mouse_down)
mouse_change_time();
} break;
case i4_event::MOUSE_BUTTON_DOWN :
{
CAST_PTR(mev, i4_mouse_button_down_event_class, ev);
if (mev->but==i4_mouse_button_down_event_class::LEFT)
{
i4_window_request_mouse_grab_class grab(this);
i4_kernel.send_event(parent,&grab);
mouse_down=i4_T;
mouse_change_time();
}
} break;
case i4_event::MOUSE_BUTTON_UP :
{
CAST_PTR(mev, i4_mouse_button_up_event_class, ev);
if (mev->but==i4_mouse_button_up_event_class::LEFT && mouse_down)
{
mouse_down=i4_F;
i4_window_request_mouse_ungrab_class grab(this);
i4_kernel.send_event(parent,&grab);
}
} break;
}
}
};
i4_button_class *g1_time_line::create_img_win(char *icon_res_name,
w32 mess_id,
i4_graphical_style_class *style)
{
i4_image_class *im=i4_load_image(g1_editor_instance.get_editor_string(icon_res_name));
I4_ASSERT(im,"icon missing");
char help[30];
sprintf(help,"%s_help",icon_res_name);
i4_object_message_event_class *omes=new i4_object_message_event_class(this, mess_id);
i4_event_reaction_class *press=new i4_event_reaction_class(this, omes);
i4_button_class *b=new i4_button_class(&g1_ges(help),
new i4_image_window_class(im, i4_T),
style,
press);
return b;
}
void g1_time_line::create_time_win(i4_graphical_style_class *style)
{
frame_show=new g1_frame_show(style, this);
frame_show->update();
i4_const_str next_str=g1_editor_instance.get_editor_string("next");
i4_window_class *frame_text=new i4_text_window_class(next_str, style);
sec_win=new g1_time_show(style, this);
w32 w=frame_text->width()+10+frame_show->width();
w32 h=frame_show->height() + 2 + sec_win->height();
i4_deco_window_class *d=new i4_deco_window_class(w,h, i4_F, style);
time_win=d;
w32 x1=d->get_x1(), y1=d->get_y1();
time_win->add_child(x1,y1+2, frame_text);
time_win->add_child(x1+frame_text->width()+5, y1, frame_show.get());
time_win->add_child(x1,y1+frame_show->height()+1, sec_win.get());
}
g1_time_line::~g1_time_line()
{
if (g1_frame_change_notify)
{
delete g1_frame_change_notify;
g1_frame_change_notify=0;
}
if (g1_scene_change_notify)
{
delete g1_scene_change_notify;
g1_scene_change_notify=0;
}
if (g1_movie_stop_notify)
{
delete g1_movie_stop_notify;
g1_movie_stop_notify=0;
}
if (scroller.get())
delete scroller.get();
if (time_win.get())
delete time_win.get();
if (bbox.get())
delete bbox.get();
if (last_scene.get())
delete last_scene.get();
if (next_scene.get())
delete next_scene.get();
if (scene_number_input.get())
delete scene_number_input.get();
}
g1_time_line::g1_time_line(i4_parent_window_class *parent,
i4_graphical_style_class *style,
g1_edit_state_class *state)
: state(state)
{
i4_object_message_event_class *o;
o=new i4_object_message_event_class(this,FRAME_CHANGED);
g1_frame_change_notify=new i4_event_reaction_class(this, o);
o=new i4_object_message_event_class(this,SCENE_CHANGED);
g1_scene_change_notify=new i4_event_reaction_class(this, o);
o=new i4_object_message_event_class(this,MOVIE_STOPPED);
g1_movie_stop_notify=new i4_event_reaction_class(this, o);
bbox=new i4_button_box_class(this, i4_F);
i4_button_class *left, *right, *rewind, *fforward;
left=create_img_win("e_left", LAST_TIME, style);
left->set_repeat_down(i4_T);
left->set_popup(i4_T);
right=create_img_win("e_right", NEXT_TIME, style);
right->set_repeat_down(i4_T);
right->set_popup(i4_T);
play=create_img_win("e_play", PLAY, style);
i4_user_message_event_class *stop=new i4_user_message_event_class(G1_STOP_MOVIE);
play->send.depress=new i4_event_reaction_class(i4_current_app, stop);
rewind=create_img_win("e_rewind", REWIND, style);
fforward=create_img_win("e_fforward", FFORWARD, style);
bbox->add_button(0,0,rewind);
bbox->add_button(0,0,left);
bbox->add_button(0,0,play.get());
bbox->add_button(0,0,right);
bbox->add_button(0,0,fforward);
bbox->arrange_down_right();
h=bbox->height();
create_time_win(style);
if (time_win->height()>h)
h=time_win->height();
last_scene=create_img_win("e_left", LAST_SCENE, style);
last_scene->set_repeat_down(i4_T);
last_scene->set_popup(i4_T);
next_scene=create_img_win("e_right", NEXT_SCENE, style);
next_scene->set_repeat_down(i4_T);
next_scene->set_popup(i4_T);
i4_const_str fmt=g1_editor_instance.get_editor_string("frame_format");
w32 scene_d=current_movie() ? current_movie()->get_scene()+1 : 1;
i4_str *scene_number=fmt.sprintf(10, scene_d);
scene_number_input=new i4_text_input_class(style,*scene_number, 40, 8, this);
delete scene_number;
sw32 xon=0;
parent->add_child(xon, parent->height()-last_scene->height()-1, last_scene.get());
xon+=last_scene->width();
parent->add_child(xon, parent->height()-scene_number_input->height()-1,
scene_number_input.get());
xon+=scene_number_input->width();
parent->add_child(xon, parent->height()-next_scene->height()-1, next_scene.get());
xon+=next_scene->width();
scroller=new g1_time_scroller(parent->width() - xon -
bbox->width() -
time_win->width(),
h, style, this);
parent->add_child(xon, parent->height()-scroller->height()-1, scroller.get());
xon+=scroller->width();
parent->add_child(xon, parent->height()-bbox->height()-1, bbox.get());
xon+=bbox->width();
parent->add_child(xon, parent->height()-time_win->height()-1, time_win.get());
}
void g1_time_line::update()
{
scroller->request_redraw(i4_F);
frame_show->update();
sec_win->request_redraw(i4_F);
}
i4_spline_class *g1_time_line::selected_spline()
{
return 0;
}
g1_movie_flow_class *g1_time_line::current_movie()
{
g1_get_current_movie_event gm;
i4_kernel.send_event(i4_current_app, &gm);
return gm.mflow;
}
void g1_time_line::set_current(w32 frame, i4_bool stop_play)
{
g1_movie_flow_class *m=current_movie();
if (m)
{
g1_editor_instance.add_undo(G1_MAP_MOVIE);
m->set_frame(frame);
i4_user_message_event_class c(G1_MAP_CHANGED);
i4_kernel.send_event(i4_current_app, &c);
update();
if (stop_play)
play->do_depress();
}
}
w32 g1_time_line::current_frame()
{
g1_movie_flow_class *m=current_movie();
if (m)
return m->get_frame();
else
return 0;
}
w32 g1_time_line::total_frames()
{
g1_movie_flow_class *m=current_movie();
if (m && m->current())
return m->current()->total_frames();
else return 0;
}
void g1_time_line::update_scene()
{
g1_movie_flow_class *m=current_movie();
i4_const_str fmt=g1_editor_instance.get_editor_string("frame_format");
i4_str *scene_number=fmt.sprintf(10, m->get_scene()+1);
scene_number_input->change_text(*scene_number);
delete scene_number;
}
void g1_time_line::set_current_scene(sw32 scene)
{
g1_editor_instance.add_undo(G1_MAP_MOVIE);
g1_movie_flow_class *m=current_movie();
m->set_scene(scene);
m->set_frame(0);
update_scene();
i4_user_message_event_class ch(G1_MAP_CHANGED);
i4_kernel.send_event(i4_current_app, &ch);
}
void g1_time_line::unpress_play()
{
if (play.get())
play->do_depress();
}
void g1_time_line::receive_event(i4_event *ev)
{
g1_movie_flow_class *m=current_movie();
CAST_PTR(oev, i4_object_message_event_class, ev);
if (!m || oev->type()!=i4_event::OBJECT_MESSAGE)
return ;
if (oev->object==this)
{
switch (oev->sub_type)
{
case LAST_TIME :
if (m->get_frame())
set_current(m->get_frame()-1, i4_T);
break;
case NEXT_TIME :
if (m->current() && m->get_frame()+1current()->total_frames())
set_current(m->get_frame()+1, i4_T);
break;
case FFORWARD :
if (m->current())
set_current(m->current()->total_frames()-1, i4_T);
break;
case REWIND :
set_current(0, i4_T);
break;
case PLAY :
{
i4_user_message_event_class m(G1_PLAY_MOVIE);
i4_kernel.send_event(i4_current_app, &m);
} break;
case LAST_SCENE :
if (m->current() && m->get_scene())
set_current_scene(m->get_scene()-1);
break;
case NEXT_SCENE :
if (m->current() && m->get_scene()t_cut_scenes-1)
set_current_scene(m->get_scene()+1);
break;
case SCENE_CHANGED :
update_scene();
break;
case FRAME_CHANGED :
update();
break;
case MOVIE_STOPPED :
unpress_play();
break;
}
} else if (oev->object==scene_number_input.get())
{
CAST_PTR(tc, i4_text_change_notify_event, ev);
i4_const_str::iterator i=tc->new_text->begin();
sw32 n=i.read_number()-1;
if (n>=0 && nt_cut_scenes)
set_current_scene(n);
}
}