/**********************************************************************
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)
***********************************************************************/
#ifndef __I4_WINDOW_HPP_
#define __I4_WINDOW_HPP_
class i4_image_class;
class i4_cursor_class;
#include "area/rectlist.hh"
#include "device/device.hh"
#include "area/rectlist.hh"
#include "device/event.hh"
#include "isllist.hh"
#include "image/context.hh"
// Brief summary :
//
// 2 Main classes are defined here :
// i4_window_class :
// base object for most everything graphical.
// An i4_window_class should only draw (using local_image) during draw().
// During draw(), proper clipping is setup.
// local_image will transform local coordinates to global space for you.
// because a window is derived from i4_event_handler_class,
// it can receive events through receive_event (see device/device.hh
// for more info on this. A the base window class does not process any events.
//
// i4_parent_window_class :
// parent windows have a list of children window.
// The draw order for children is painter's algorithm. So the last
// child in the list gets drawn on top. parent windows also
// maintain a dirty_area list so that redraw can be done
// more efficiently than redrawing themselves & their children completely.
// parent windows have a default behavior for responding to a
// number of events. parent windows keep a mouse & keyboard
// focus. The mouse focus is set automically through mouse_move events.
// The key focus is not implemented yet.
//
class i4_parent_window_class;
class i4_window_class : public i4_event_handler_class
{
protected:
// Data members you need not worry about
i4_image_class *global_image; // pointer to the image associated with the display we draw on
i4_coord global_x,global_y, // returned by x() & y()
mouse_x, mouse_y;
w16 w,h;
i4_bool redraw_flag;
i4_image_class *local_image; /* this will transform all drawing coordinates
from local-space to glabal space
plus when drawing is done from draw()
proper clipping for you window is setup beforehand */
i4_parent_window_class *parent; // this may be 0
i4_cursor_class *cursor;
public:
// next pointer is used by i4_parent_window_class's isl_list
i4_window_class *next;
virtual void receive_event(i4_event *ev);
// initially when a window is created it has no parent
i4_window_class(w16 w, w16 h);
i4_coord x() { return global_x; }
i4_coord y() { return global_y; }
w16 width() { return w; }
w16 height() { return h; }
i4_coord last_mouse_x() { return mouse_x; } // last position in the window mouse was at
i4_coord last_mouse_y() { return mouse_y; }
// forget redraw is called by a parent if the child had ask for a redraw but
// when the parent got around to doing the redraw, the child was clipped away
virtual void forget_redraw() { redraw_flag=i4_F; }
// request draw should be called in the calculating part of a windows processing
// the windows draw() function will then be called later with the correct clip list
// 2 versions of request_redraw exist, one redraws
// everything, and one tells of a specific area to redraw
// a window may call request_redraw() within it's draw() to display continual animations
virtual void request_redraw(i4_bool for_a_child=i4_F);
// x1, y1, x2, y2 are in local-space coordinates
// this used to be called request_redraw, but it got confused with regular request_redraw
// this is called whan a window's area becomes visible when it wasn't before
virtual void note_undrawn(i4_coord x1, i4_coord y1, i4_coord x2, i4_coord y2,
i4_bool propogate_to_children=i4_T);
// a parent uses this to determine that you need to have your draw() function called
virtual i4_bool need_redraw() { return redraw_flag; }
// draw is called by parent sometime after request_draw() is called
// this draw may not occur if window is clipped away, in which case forget_redraw() is called
virtual void draw(i4_draw_context_class &context);
// move can be used to a change window's position
// within a window, to give a window a draw_area and parent or both
// move will also send a notify_move event to it's parent
// (if it has one), whereas private_move will not
// if draw_under is false the parent will not draw under
//the dirty area the window's movement created
virtual void move(i4_coord x_offset, i4_coord y_offset, i4_bool draw_under=i4_T);
// private move will not notify it's parent, and should
// probably only be called by the parent.
virtual void private_move(i4_coord new_x, i4_coord new_y);
// private resize will not notify it's parent, and
// should probably only be called by your parent
virtual void private_resize(w16 new_width, w16 new_height);
virtual void reparent(i4_image_class *draw_area, i4_parent_window_class *parent);
// resize will change the width and height of our window and notify our parent of the change
virtual void resize(w16 new_width, w16 new_height);
// this sets the mouse image to displayed when the cursor
// enters this window. The actual act of changing the cursor
// is done by i4_window_class::receive_event() on GOT & LOST mouse
// focus events. So a derived window must remember to call
// the shadowed receive_event or the cursor will not change.
// If cursor is 0, then the cursor will not change
// shape when it enters this window.
virtual void set_cursor(i4_cursor_class *cursor);
virtual ~i4_window_class();
void show_context(i4_draw_context_class &context);
i4_bool isa_parent(i4_window_class *who);
virtual i4_parent_window_class *root_window();
// if this is true, then parent will not clip you out when it draws
virtual i4_bool transparent() { return i4_F; }
i4_parent_window_class *get_parent() { return parent; }
#ifndef I4_RETAIL
void debug_show();
#endif
};
class i4_parent_window_class : public i4_window_class
{
private:
i4_bool mouse_focus_grabbed, have_mouse_focus;
i4_bool child_rerequested_redraw;
void send_event_to_child(i4_window_class *w, i4_event *ev);
protected:
i4_bool child_need_redraw;
virtual void private_move(i4_coord x_offset, i4_coord y_offset);
typedef i4_isl_list win_list;
typedef i4_isl_list::iterator win_iter;
win_list children;
win_iter key_focus, mouse_focus, drag_drop_focus;
// Note:
// so a parent can refresh itself and children more efficiently it keeps a list of dirty area.
// this is kept in global coordinates for several reasons. It is important to note that
// request_redraw(x1,y1,x2,y2) takes coordinates in local_space, but transforms them to
// local space when adding to dirty_area
i4_rect_list_class undrawn_area;
// These functions shouldn't really be needed by derived classes
void change_key_focus(i4_window_class *new_focus);
void change_mouse_focus(i4_window_class *new_focus);
void redraw_area(i4_coord x1, i4_coord y1, i4_coord x2, i4_coord y2); // in local coordinates
win_iter find_window(i4_coord mouse_x, i4_coord mouse_y);
void drag_drop_move(i4_event *ev);
void mouse_move(i4_event *ev);
public:
i4_bool has_mouse_focus() { return have_mouse_focus; }
virtual i4_bool find_new_mouse_focus(); // return true if focus changed
virtual i4_parent_window_class *root_window();
virtual void resize(w16 new_width, w16 new_height);
virtual void reparent(i4_image_class *draw_area, i4_parent_window_class *parent);
// these functions are called when REQUEST_NEXT_FOCUS, etc. events are recieved
// so that you can over-ride these event functionalities if you want
virtual void next_key_focus();
virtual void left_key_focus();
virtual void right_key_focus();
virtual void up_key_focus();
virtual void down_key_focus();
// Because a parent window needs to tells it's children
// to draw() as well and setup proper clipping for itself
// a parent_draw() function is supplied which is called by draw() which is where all drawing
// done by a derived class of i4_window_class should go. parent_draw() will have the correct clipping
// list (including the exclusion of it's children.
virtual void draw(i4_draw_context_class &context);
// see comment's above draw(), this function should be used by derived class instead of draw()
virtual void parent_draw(i4_draw_context_class &context);
// receive_event is a general event notification routine.
// If you get a event and note that you cannot handle it, you should
// pass it on down to you derived parent so that functionality still works
// example receive_event :
// void receive_event(i4_event *ev)
// {
// if (ev->type==i4_event::MOUSE_MOVE)
// {
// do something
// } else i4_parent_window_class::receive_event(ev);
// }
virtual void receive_event(i4_event *ev);
// forget redraw is called by a parent if the child had ask for a redraw but
// when the parent got around to doing the redraw, the child was clipped away
// for the parent window case, undrawn_area is discarded and all
// children's forget_redraw are called
virtual void forget_redraw();
i4_parent_window_class(w16 w, w16 h);
// x & y are relative to parent x,y (added to end of window list)
virtual void add_child(i4_coord x, i4_coord y, i4_window_class *child);
// x & y are relative to parent x,y (added to front of window list)
virtual void add_child_front(i4_coord x, i4_coord y, i4_window_class *child);
// does not delete the child, simply removes and request redraw under its area
virtual void remove_child(i4_window_class *child);
// removes all children from self and addes them into other_parent
void transfer_children(i4_parent_window_class *other_parent,
i4_coord x_offset, i4_coord y_offset);
// arranges child windows from left to right then down
virtual void arrange_right_down();
// arranges child windows from top to bottom then right
virtual void arrange_down_right();
// makes the window the minimum size needed to fit all children
virtual void resize_to_fit_children();
// adds all local area to undrawn_area
virtual void request_redraw(i4_bool for_a_child=i4_F);
// adds this area to undrawn_area (in local coordinates)
virtual void note_undrawn(i4_coord x1, i4_coord y1, i4_coord x2, i4_coord y2,
i4_bool propogate_to_children=i4_T);
virtual i4_bool need_redraw()
// returns true if we have any dirty area or childen report they need redrawing
{ return (i4_bool)(!undrawn_area.empty()|
child_need_redraw |
i4_window_class::need_redraw()); }
virtual i4_window_class *get_nth_window(w32 win_num);
i4_bool isa_child(i4_window_class *w);
virtual ~i4_parent_window_class();
};
#endif