/**********************************************************************
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/style.hh" #include "window/window.hh" #include "device/kernel.hh" #include "window/dragwin.hh" #include "window/colorwin.hh" #include "image/image.hh" #include "menu/boxmenu.hh" #include "window/win_evt.hh" #include "gui/text.hh" #include "gui/deco_win.hh" #include "app/app.hh" #include "gui/gradiant.hh" class i4_mwm_context_help : public i4_window_class { i4_graphical_style_class *style; i4_str *text; public: i4_event_handler_reference_classshadow; void draw(i4_draw_context_class &context) { i4_font_class *f=style->font_hint->small_font; local_image->clear(style->color_hint->text_background, context); local_image->rectangle(0,0, width()-1, height()-1, 0, context); f->set_color(style->color_hint->text_foreground); f->put_string(local_image, 2,2, *text, context); } i4_mwm_context_help(i4_graphical_style_class *style, const i4_const_str text) : style(style), i4_window_class(style->font_hint->small_font->width(text)+4, style->font_hint->small_font->height(text)+4), text(new i4_str(text)) { } ~i4_mwm_context_help() { delete text; if (shadow.get()) i4_kernel.delete_handler(shadow.get()); } char *name() { return "i4_mwm_context_help"; } }; class i4_mwm_style_class : public i4_graphical_style_class { public: i4_image_class *close_icon; virtual void uninit() { if (close_icon) { delete close_icon; close_icon=0; } i4_graphical_style_class::uninit(); } char *name() { return "MWM"; } virtual i4_parent_window_class *create_mp_window(i4_coord x, i4_coord y, w16 w, w16 h, const i4_const_str &title, i4_event_reaction_class *on_delete=0 ); virtual i4_bool close_mp_window(i4_parent_window_class *created_window) { if (!created_window) return i4_F; i4_parent_window_class *to_del=created_window->get_parent(); if (!to_del) return i4_F; i4_parent_window_class *to_del_parent=to_del->get_parent(); if (!to_del_parent) return i4_F; i4_kernel.delete_handler(to_del); return i4_T; } virtual i4_bool available_for_display(i4_display_class *whom) { return i4_T; } virtual i4_menu_class *create_menu(i4_bool hide_on_pick) { return new i4_box_menu_class(this,hide_on_pick); } virtual void get_in_deco_size(w32 &left, w32 &top, w32 &right, w32 &bottom) { left=right=top=bottom=2; } virtual void get_out_deco_size(w32 &left, w32 &top, w32 &right, w32 &bottom) { left=right=top=bottom=2; } virtual void deco_neutral_fill(i4_image_class *screen, sw32 x1, sw32 y1, sw32 x2, sw32 y2, i4_draw_context_class &context) { i4_rect_list_class sub_clip(&context.clip,0,0); sub_clip.intersect_area(x1,y1,x2,y2); sub_clip.swap(&context.clip); i4_image_class *im=icon_hint->background_bitmap; if (im) { int iw=im->width(), ih=im->height(); int dx1=-context.xoff; int dy1=-context.yoff; while (dx1+iw put_image(screen, x,y, context); } else screen->clear(color_hint->neutral(), context); sub_clip.swap(&context.clip); } // draw a decoration around an area that looks like it's pressed into the screen virtual void draw_in_deco(i4_image_class *screen, i4_coord x1, i4_coord y1, i4_coord x2, i4_coord y2, i4_bool active, i4_draw_context_class &context) { i4_color_hint_class::bevel *color; if (active) color=&color_hint->window.active; else color=&color_hint->window.passive; screen->add_dirty(x1,y1,x2,y1+1,context); screen->add_dirty(x1,y1+2,x1+1,y2,context); screen->add_dirty(x1+2,y2-1,x2,y2,context); screen->add_dirty(x1-1,y1+2,x2,y2-2,context); screen->bar(x1,y1,x2,y1,color->dark,context); screen->bar(x1,y1,x1,y2,color->dark,context); screen->bar(x1+1,y1+1,x2-1,y1+1,color_hint->black,context); screen->bar(x1+1,y1+1,x1+1,y2-1,color_hint->black,context); screen->bar(x1+1,y2,x2,y2,color->bright,context); screen->bar(x2,y1+1,x2,y2,color->bright,context); screen->bar(x1+2,y2-1,x2-1,y2-1,color->medium,context); screen->bar(x2-1,y1+1,x2-1,y2-1,color->medium,context); } // draw a decoration around an area that looks like it sticks out the screen virtual void draw_out_deco(i4_image_class *screen, i4_coord x1, i4_coord y1, i4_coord x2, i4_coord y2, i4_bool active, i4_draw_context_class &context) { i4_color_hint_class::bevel *color; if (active) color=&color_hint->window.active; else color=&color_hint->window.passive; screen->add_dirty(x1,y1,x2,y1+1,context); screen->add_dirty(x1,y1+2,x1+1,y2,context); screen->add_dirty(x1+2,y2-1,x2,y2,context); screen->add_dirty(x1-1,y1+2,x2,y2-2,context); screen->bar(x1,y1,x2,y1,color->bright,context); screen->bar(x1,y1,x1,y2,color->bright,context); screen->bar(x1+1,y1+1,x2-1,y1+1,color->medium,context); screen->bar(x1+1,y1+1,x1+1,y2-1,color->medium,context); screen->bar(x1+1,y2,x2,y2,color->dark,context); screen->bar(x2,y1+1,x2,y2,color->dark,context); screen->bar(x1+2,y2-1,x2-1,y2-1,color_hint->black,context); screen->bar(x2-1,y1+1,x2-1,y2-1,color_hint->black,context); } // this will create a temporary (quick) context help window at the mouse cursor // you are responsible for deleting the window virtual i4_window_class *create_quick_context_help(int mouse_x, int mouse_y, const i4_const_str &str) { i4_parent_window_class *parent=i4_current_app->get_root_window(); i4_mwm_context_help *w=new i4_mwm_context_help(this, str); if (w->width()+mouse_x+3 > parent->width()) mouse_x=parent->width()-w->width()-3; if (w->height()+mouse_y+3 > parent->height()) mouse_y=parent->height()-w->height()-3; i4_window_class *cw=new i4_color_window_class(w->width(), w->height(), 0, this); w->shadow=cw; parent->add_child(mouse_x+3, mouse_y+3, cw); parent->add_child(mouse_x, mouse_y, w); return w; } } mwm_style; class i4_mwm_event_class : public i4_user_message_event_class { public: enum { CLOSE_YOURSELF, MAXIMIZE_YOURSELF } ; i4_window_class *from; i4_mwm_event_class(w8 sub_type, i4_window_class *from) : i4_user_message_event_class(sub_type),from(from) {} virtual i4_event *copy() { return new i4_mwm_event_class(sub_type,from); } }; static void widget(i4_image_class *im, i4_coord x1, i4_coord y1, i4_coord x2, i4_coord y2, i4_color bright, i4_color med, i4_color dark, i4_draw_context_class &context) { // to keep from creating a dirty for each operation below im->add_dirty(x1,y1,x2,y2,context); im->bar(x1,y1,x2,y1,bright,context); im->bar(x1,y1+1,x1,y2,bright,context); im->bar(x2,y1+1,x2,y2,dark,context); im->bar(x1+1,y2,x2-1,y2,dark,context); im->bar(x1+1,y1+1,x2-1,y2-1,med,context); } class i4_mwm_close_button_class : public i4_window_class { private: i4_graphical_style_class *hint; i4_bool active; public: char *name() { return "close_button"; } i4_mwm_close_button_class(w16 w, w16 h,i4_graphical_style_class *hint) : i4_window_class (w,h),hint(hint) { active=i4_F; } void activate(i4_bool yes) { active=yes; request_redraw(); } virtual void receive_event(i4_event *ev) { i4_mwm_event_class c(i4_mwm_event_class::CLOSE_YOURSELF,this); if (ev->type()==i4_event::MOUSE_BUTTON_DOWN && parent) i4_kernel.send_event(parent,&c); } void draw(i4_draw_context_class &context) { i4_color_hint_class::bevel *color; /* if (active) color=&hint->color_hint->window.active; else */ color=&hint->color_hint->window.passive; local_image->add_dirty(0,0,width()-1,height()-1,context); widget(local_image, 0,0,width()-2,height()-2,color->bright,color->medium,color->dark,context); local_image->bar(0,height()-1,width()-1,height()-1,hint->color_hint->black,context); local_image->bar(width()-1,0,width()-1,height()-1,hint->color_hint->black,context); mwm_style.icon_hint->close_icon->put_image(local_image,2,2,context); } virtual void show_self(w32 indent) { char fmt[50]; sprintf(fmt,"%%%ds mwm_close_button",indent); i4_warning(fmt," "); } } ; static inline int get_res_num(char *name, int def) { i4_const_str s=i4_string_man.get(name); if (s.null()) return def; i4_const_str::iterator i=s.begin(); int r=i.read_number(); int g=i.read_number(); int b=i.read_number(); return (r<<16)|(g<<8)|b; } // this is the top draggable part of a window class i4_mwm_drag_bar_class : public i4_window_class { private: i4_graphical_style_class *hint; i4_bool active,dragging; public: i4_const_str title; char *name() { return "drag_bar"; } enum { MIN_WIDTH=15 }; i4_mwm_drag_bar_class(w16 w, w16 h, const i4_const_str &title, i4_graphical_style_class *hint) : i4_window_class(w,h), hint(hint), title(title) { active=i4_F; dragging=i4_F; } void activate(i4_bool yes) { active=yes; request_redraw(); } void draw(i4_draw_context_class &context) { i4_color_hint_class::bevel *color; if (active) color=&hint->color_hint->window.active; else color=&hint->color_hint->window.passive; local_image->add_dirty(0,0,width()-1,height()-1,context); local_image->rectangle(0,0,width()-1,height()-1,hint->color_hint->black,context); i4_color sc,ec; if (active) { sc=get_res_num("drag_bar_gradiant_active_start", 0x80); ec=get_res_num("drag_bar_gradiant_active_end", 0x20); } else { sc=get_res_num("drag_bar_gradiant_start", 0x707070); ec=get_res_num("drag_bar_gradiant_end", 0x202020); } i4_gradiant_bar(local_image, 1,1,width()-2,height()-2, sc, ec, context); // if (dragging) // local_image->widget(1,1,width()-2,height()-2, // color->dark,color->medium,color->bright,context); // else // local_image->widget(1,1,width()-2,height()-2, // color->bright,color->medium,color->dark,context); i4_font_class *font=hint->font_hint->normal_font; w16 strw=font->width(title); w16 strh=font->height(title); font->set_color(0xffffff); font->put_string(local_image,width()/2-strw/2,height()/2-strh/2,title,context); } virtual void receive_event(i4_event *ev) { if (ev->type()==i4_event::MOUSE_BUTTON_DOWN) { if (!dragging) { i4_window_request_drag_start_class drag(this); i4_kernel.send_event(parent,&drag); if (drag.return_result) { dragging=i4_T; request_redraw(); } } } else if (ev->type()==i4_event::MOUSE_BUTTON_UP) { if (dragging) { i4_window_request_drag_end_class end_drag(this); i4_kernel.send_event(parent,&end_drag); dragging=i4_F; request_redraw(); } } } }; class i4_mwm_window_class : public i4_draggable_window_class { private: i4_graphical_style_class *hint; i4_mwm_drag_bar_class *drag; i4_mwm_close_button_class *close_button; i4_bool active,draw_frame; w16 left,right,top,bottom; i4_parent_window_class *user_area; i4_event_reaction_class *on_delete; w32 close_button_width(i4_graphical_style_class *style) { return 2+style->icon_hint->close_icon->width()+3; } w32 close_button_height(i4_graphical_style_class *style) { return 2+style->icon_hint->close_icon->height()+3; } w32 dragbar_height(i4_graphical_style_class *style, const i4_const_str &title) { return hint->font_hint->normal_font->height(title)+4+1; } public: ~i4_mwm_window_class() { if (on_delete) delete on_delete; on_delete = 0; } i4_parent_window_class *user_window() { return user_area; } i4_mwm_window_class(w16 width, w16 height, const i4_const_str &title, i4_graphical_style_class *hint, i4_event_reaction_class *on_delete) : i4_draggable_window_class(width,height), hint(hint), on_delete(on_delete) { left=2; if (close_button_height(hint)>dragbar_height(hint,title)) top=close_button_height(hint); else top=dragbar_height(hint,title); top+=2; // top border right=2; bottom=2; active=i4_F; draw_frame=i4_T; resize(w+left+right,h+top+bottom); drag=new i4_mwm_drag_bar_class(w-left-right-close_button_width(hint), top-2, title,hint); add_child(2,2,drag); close_button=new i4_mwm_close_button_class(close_button_width(hint), close_button_height(hint), hint); add_child(w-right-close_button_width(hint),2,close_button); user_area=i4_add_color_window(this, hint->color_hint->window.passive.medium, hint, left, top, width, height); } virtual void parent_draw(i4_draw_context_class &context) { if (draw_frame || !undrawn_area.clipped_away(0,0,0+width()-1,0+1) || !undrawn_area.clipped_away(0,0,0+1,0+height()-1) || !undrawn_area.clipped_away(0+1,0+height()-2,0+width()-1,0+height()-1) || !undrawn_area.clipped_away(0+width()-2,0,0+width()-1,0+height()-1)) { i4_color_hint_class::bevel *color; if (active) color=&hint->color_hint->window.active; else color=&hint->color_hint->window.passive; local_image->add_dirty(0,0,width()-1,1,context); local_image->add_dirty(0,2,1,height()-1,context); local_image->add_dirty(2,height()-2,width()-1,height()-1,context); local_image->add_dirty(width()-2,2,width()-1,height()-3,context); local_image->bar(0,0,width()-1,0,color->medium,context); local_image->bar(0,1,0,height()-1,color->medium,context); local_image->bar(1,1,width()-2,1,color->bright,context); local_image->bar(1,2,1,height()-2,color->bright,context); local_image->bar(width()-2,2,width()-2,height()-2,color->medium,context); local_image->bar(2,height()-2,width()-3,height()-2,color->medium,context); local_image->bar(width()-1,0,width()-1,height()-1,hint->color_hint->black,context); local_image->bar(0,height()-1,width()-2,height()-1,hint->color_hint->black,context); draw_frame=i4_F; } if (!undrawn_area.empty()) local_image->bar(2,2,width()-3,height()-3,hint->color_hint->window.passive.medium,context); } virtual i4_bool need_redraw() { return (i4_bool)(i4_parent_window_class::need_redraw()|draw_frame); } void receive_event(i4_event *ev) { if (ev->type()==i4_event::WINDOW_MESSAGE) { CAST_PTR(f,i4_window_message_class,ev); if (f->sub_type==i4_window_message_class::GOT_MOUSE_FOCUS) { active=i4_T; drag->activate(i4_T); close_button->activate(i4_T); draw_frame=i4_T; } else if (f->sub_type==i4_window_message_class::LOST_MOUSE_FOCUS) { drag->activate(i4_F); close_button->activate(i4_F); active=i4_F; draw_frame=i4_T; } else if (f->sub_type==i4_window_message_class::NOTIFY_RESIZE) { CAST_PTR(res,i4_window_notify_resize_class,ev); i4_mwm_window_class *new_parent=new i4_mwm_window_class(res->new_width, res->new_height, drag->title, hint, on_delete ? on_delete->copy() : 0); user_area->transfer_children(new_parent->user_area,0,0); // this will be post-poned i4_kernel.delete_handler(this); parent->add_child(x(),y(),new_parent); } i4_draggable_window_class::receive_event(ev); } else if (ev->type()==i4_event::USER_MESSAGE) { CAST_PTR(f,i4_mwm_event_class,ev); if (f->sub_type==i4_mwm_event_class::CLOSE_YOURSELF) { if (on_delete) i4_kernel.send(on_delete); i4_kernel.delete_handler(this); } } else i4_draggable_window_class::receive_event(ev); } } ; i4_parent_window_class *i4_mwm_style_class::create_mp_window(i4_coord x, i4_coord y, w16 w, w16 h, const i4_const_str &title, i4_event_reaction_class *on_delete) { i4_parent_window_class *parent=i4_current_app->get_root_window(); i4_mwm_window_class *win=new i4_mwm_window_class(w,h,title,this,on_delete); if (x==-1) x=parent->width()/2-w/2; if (y==-1) y=parent->height()/2-h/2; parent->add_child(x,y,win); return win->user_window(); }