Gem, which stands for the "Graphics and Events Manager", can be used independent of most of the rest of the Amulet. Gem uses the wrapper mechanism (for styles and fonts), but it does not use the ORE object system.
gem.h
. Gem also uses types.h
for wrappers, gdefs.h
for styles, images, point lists, and fonts, and idefs.h
for the input events. For a complete description of Amulet include files and how to use them, see Section 1.6 in the Overview chapter.
7.3 Drawonables
The primary data structure in gem is the Am_Drawonable
, which is a C++ object that corresponds to a window-manager window or off-screen buffer (for example, in X/11 it corresponds to a "drawable"). We called it a "Drawonable" because it is something that you can draw on. We also wanted to reserve the word "Window" for the Opal level object that corresponds to the drawonable. In this manual, sometimes "window" is used for "drawonable" since drawonables are implemented as window-manager windows.7.3.1 Creating Drawonables
Programmers create a "root" drawonable at initialization, and then create other drawonables as children of the root (or as children of another drawonable). The typical initialization is:Am_Drawonable *root = Am_Drawonable::Get_Root_Drawonable();
At the Opal level, this is called automatically by Am_Initialize
to set up the exported Am_Screen
object. Under X/11, Get_Root_Drawonable
takes an optional string parameter which is the name of the screen. You can call therefore call Get_Root_Drawonable
multiple times to support multiple screens.Create
method. If you use root.Create
you get a top-level window, and if you use another drawonable, then it creates a sub-window. All of the parameters of the create call are optional, and are:
int l = 0
: the left of the new window in the coordinates of its parent.
int t = 0
: the top of the window
unsigned int w = 100
: width of the window
unsigned int h = 100
: height
const char* tit = ""
: the title for the window
const char* icon_tit = ""
: the string to display with the icon for the window.
bool vis = true
: whether the window is initially visible on the screen on not.
bool initially_iconified = false
: whether the window starts out as an icon.
Am_Style back_color = Am_No_Style
: the initial color for the background of the window.
unsigned int border_w = 2
: the size of the border of the window. This is ignored by most window managers for the top-level windows.
bool save_under_flag = false
: save the bitmaps underneath the window (useful for pop-up menus).
int min_w = 1
: The minimum size allowed for this window (when the user or program resizes it). You can't have 0 size windows.
int min_h = 1
: Minimum height.
int max_w = 0
: The maximum width allowed for the window. 0 is illegal so means no maximum.
int max_h = 0
: Maximum height.
bool title_bar_flag = true
: Whether the title line is displayed or not. Under X/11 having no title line means the window is not managed by the window manager.
bool query_user_for_position = false
: If true, then the initial left and top are ignored and the user is queried instead.
bool query_user_for_size = false
: If true, then the initial width and height are ignored and the user is queried instead.
bool clip_by_children_flag = true
: If false, then graphics drawn on the window show through all children windows (drawonables) created as children of this window.
Am_Input_Event_Handlers *evh = NULL) = 0
: How input is handled for this window, see Section 7.5.1.
virtual Am_Drawonable* Create_Offscreen (
int width = 0, int height = 0,
Am_Style background_color = Am_No_Style) = 0;
Am_Drawonable* Am_Drawonable::Narrow (Am_Ptr ptr
): given an arbitrary pointer, this casts it to be a Am_Drawonable
. Because drawonables are not wrappers, no checking is done.
void Destroy ()
: Destroys the drawonable and all its children (including removing them from the screen).
bool Inquire_Window_Borders(int& left_border, int& top_border, int& right_border, int& bottom_border, int& outer_left, int& outer_top)
: return the current window border sizes. For X/11, this may be inaccurate for windows that are not yet visible.
void Raise_Window (Am_Drawonable *target_d)
: Move the window to the "top" of all its siblings in Z order. If target_d
is NULL, then the window is moved so it is not covered by any other windows. If target_d
is a valid Am_Drawonable, then the window is put above target_d
in Z order.
void Lower_Window (Am_Drawonable *target_d)
: Move the window to the "bottom" of all its siblings (if target_d
is NULL), or just until it is below target_d
.
void Set_Iconify (bool iconified)
: Make the window be iconified or not iconified.
void Set_Title (const char* new_title)
: Change window title.
void Set_Icon_Title (const char* new_title)
: Change icon title.
void Set_Position (int new_left, int new_top)
: Move the drawonable.
void Set_Size (unsigned int new_width, unsigned int new_height)
: Change the size.
void Set_Max_Size (unsigned int new_width, unsigned int new_height)
: Change the maximum size.
void Set_Min_Size (unsigned int new_width, unsigned int new_height)
: Change the minimum size.
void Set_Visible (bool vis)
: Make the window visible or not.
void Set_Border(bool new_title_bar, unsigned int new_width)
: Set whether has a title bar and how thick the border is.
void Set_Background_Color (Am_Style new_color)
bool Get_Iconify ()
const char* Get_Title ()
const char* Get_Icon_Title ()
void Get_Position (int& l, int& t)
: Sets l and t with current left and top.
void Get_Size (int& w, int& h)
void Get_Max_Size (int& w, int& h)
void Get_Min_Size (int& w, int& h)
bool Get_Visible ()
void Get_Border (bool& title_bar_flag, unsigned int& width)
Am_Style& Get_Background_Color ()
int Get_Depth ()
: Returns the current pixel depth in bits (e.g. 8 for 8-bit color).
bool Is_Color ()
: Returns true if the window is color or false
if not.
void Get_Values (int& l, int& t, int& w, int& h, const char*& tit, const char*& icon_tit, bool& vis, bool& iconified_now, Am_Style& back_color, unsigned int& border_w, bool& save_under_flag, int& min_w, int& min_h, int& max_w, int& max_h, bool& title_bar_flag, bool& clip_by_children_flag, int& bit_depth)
: returns all of the parameters at once.
The actual pixels drawn in a drawonable by the various drawing routines are described in detail in the Opal chapter of the Amulet manual. The Opal objects' slots are passed as parameters to the Gem level drawing routines. The
Am_Style, Am_Image_Array
, and Am_Font
structures are also described there. That information will not be repeated here.
void Beep()
: Causes a sound on the machine this drawonable is displayed on. This is called by the Opal-level Am_Beep()
routine.
void Set_Cursor(Am_Image_Array image, Am_Image_Array mask, Am_Style fg_color, Am_Style bg_color)
: Set the cursor for the drawonable. The mouse pointer will display the specified cursor whenever the mouse is within the bounds of this drawonable, and it will display the default cursor whenever the mouse exits a drawonable with a specific cursor. Amulet does not support setting a cursor globally, so that it has a custom image no matter where the mouse is pointing.
virtual void Bitblt (int d_left, int d_top, int width, int height, Am_Drawonable* source, int s_left, int s_top, Am_Draw_Function df = Am_DRAW_COPY)
: Bitblt copies a rectangular area from one drawonable to another, using the specified drawing function. The destination for bitblt is the Am_Drawonable
this message is sent to.
void Clear_Area (int left, int top, int width, int height)
: This clears a rectangular region in the drawonable to the drawonable's backgound style.
void Flush_Output()
: This causes all pending output to be displayed on the screen. Under X/11, you will not see any graphics until this is called, unless you're running an event loop. Calling this routine is not strictly necessary on the PC or Mac, but you should call it occasionally to maintain machine independancy.
void Translate_Coordinates (int src_x, int src_y, Am_Drawonable *src_d, int& dest_x_return, int& dest_y_return)
: Convert the coordinates in one window to be coordinates in another window. To translate to or from screen coordinates, pass the root drawonable as the source or destination drawonable. Translating coordinates from a child of one root drawonable to a child of another root causes an Am_Error()
. If the source or destination drawonable are offscreen drawonables, an Am_Error()
will result.
void Translate_From_Virtual_Source (int src_x, int src_y, bool title_bar, int border_width, int& dest_x_return, int& dest_y_return)
:
Translates a point from drawonable that hasn't neccessarily been created to screen coordinates. This function only works on root drawonables.
void Get_Image_Size (Am_Image_Array& image, int& ret_width, int& ret_height)
: Sets ret_width
and ret_height
with
the width and height of the specified image array as if it were displayed on this drawonable.
int Get_Char_Width (Am_Font Am_font, char c)
: Returns the width in pixels of character c
as if displayed in the font Am_font
on this drawonable.
int Get_String_Width (Am_Font Am_font, const char* the_string, int the_string_length):
Returns the width, in pixels, of the first the_string_length
characters of the_string
, as if it were displayed in font Am_font
on this drawonable
void Get_String_Extents (Am_Font Am_font, const char* the_string, int the_string_length, int& width, int& ascent, int& descent, int& left_bearing, int& right_bearing):
This returns the extents of the first the_string_length
characters of the_string
, as if drawn in font Am_font
on this drawonable. The total height of the bounding rectangle for this string is ascent + descent
. left_bearing
is the distance from the origin of the text to the first "inked" pixel. The right_bearing
is the distance from the origin of the text to the last "inked" pixel.
void Get_Font_Properties (Am_Font Am_font, int& max_char_width, int& min_char_width, int& max_char_ascent, int& max_char_descent):
The max ascent
and max_descent
include vertical spacing between rows of text. The max_char_width
and min_char_width
are the width, in pixels, of the widest and narrowest characters in Am_font
on this drawonable.
There is only one clip mask per root drawonable. All drawonables which have the same root share the same clip region. It is necessary to set the clip region for each window before drawing the contents of that window. For efficiency, it's a good idea to complete drawing in one window before resetting the clip region and drawing in other windows.
The clip region can be set with a rectangular region, or with an arbitrarily shaped Am_Region. Regions are described in Section 7.4.4. The root drawonable stores a stack of clipping regions. Use
Push_Clip()
and Pop_Clip()
to push regions onto this stack, or to pop them off. The current clip region is the intersection of all of the regions currently on the stack.
void Clear_Clip():
Clear the clip region and empty the clip region stack: no clipping will occur.
void Set_Clip (Am_Region* region):
This empties the clip region stack and sets the clipping region to the specified Am_Region.
void Set_Clip (short left, short top, unsigned short width,unsigned short height):
This empties the clip region stack and sets the clipping region to the rectangular region specified by left
, top
, width
, and height.
void Push_Clip (Am_Region* region):
This pushes the specified Am_Region
onto the drawonable's clip region stack.
void Push_Clip (short left, short top, unsigned short width, unsigned short height)
: This pushes the rectangular region specified by left
, top
, width
, and height
onto the drawonable's clip region stack.
void Pop_Clip ()
: This pops the most recently pushed region off of the drawonable's clip region stack. Popping when there's nothing on the stack is silently ignored.
In_Clip()
routines provide a way to ask a drawonable if a point is inside its clip region. When asking if a given region is inside the drawonable's clip region, you can use the total
parameter to determine whether the given region is completely inside the clip region, or whether it just intersects it.
bool In_Clip (short x, short y)
: Returns true
if the point (x,y)
is inside this drawonable's clip region, and false
otherwise.
bool In_Clip (short left, short top, unsigned short width, unsigned short height, bool &total)
: Returns true
if the rectangular region specified by left
, top
, width
, and height
intersects this drawonable's clip region. total
is set to true
if the clip region completely contains the rectangle, and false
if part of the rectangle is outside the clip region.
bool In_Clip (Am_Region *rgn, bool &total)
: Returns true
if region
intersects this drawonable's clip region. total
is set to true
if the clip region completely contains region
, and false
if part of it is outside the clip region.
Am_Region
class describe arbitrarily shaped regions. Am_Region
is a generalization of a drawonable's clip region, discussed in Section 7.4.3. By using the member functions listed below, you can build a region of arbitrary shape to install as the clip region of a drawonable.
class Am_Region {
public:
static Am_Region* Create ();
virtual void Destroy () = 0;
virtual void Clear () = 0;
virtual void Set (short left, short top, unsigned short width,
unsigned short height) = 0;
virtual void Push (Am_Region* region) = 0;
virtual void Push (short left, short top, unsigned short width,
unsigned short height) = 0;
virtual void Pop () = 0;
virtual void Union (short left, short top, unsigned short width,
unsigned short height) = 0;
virtual void Intersect (short left, short top, unsigned short width,
unsigned short height) = 0;
virtual bool In (short x, short y) = 0;
virtual bool In (short left, short top, unsigned short width,
unsigned short height, bool &total) = 0;
virtual bool In (Am_Region *rgn, bool &total) = 0;
};
7.4.5 Drawing Functions
All of the drawing functions take a Am_Draw_Function
parameter
which controls how the pixels of the drawn shape affect the screen. Since most programmers will use color screens, draw functions are not usually useful. The supported values for Am_Draw_Function
are Am_DRAW_COPY, Am_DRAW_OR
and Am_DRAW_XOR
.ls
and fs
specify the line style and fill style for the drawing operations.
void Draw_Arc (Am_Style ls, Am_Style fs, int left, int top, unsigned int width, unsigned int height, int angle1 = 0, int angle2 = 360, Am_Draw_Function f = Am_DRAW_COPY, Am_Arc_Style_Flag asf = Am_ARC_PIE_SLICE )
: Draw an optionally filled arc. To draw a circle, let angle2
= 360.
void Draw_Image (int left, int top, int width, int height, Am_Image_Array image, int i_left = 0, int i_top = 0, Am_Style ls = Am_No_Style, Am_Style fs = Am_No_Style, Am_Draw_Function f = Am_DRAW_COPY)
: This draws the contents of an Am_Image_Array
onto this drawonable. Bitmaps are treated differently than GIF pixmaps. With bitmaps, ls
is used to control the color of 'on' bits, and fs
is used for the background behind the image. If fs
is Am_No_Style
, the background pixels will be transparent- whatever was behind the image will show through. We do not support transparent GIF images on X/11 platforms. For GIFs and full color pixmaps, fs
and ls
are ignored.
void Get_Polygon_Bounding_Box (Am_Point_List pl, Am_Style ls, int& out_left, int& out_top int& width, int& height)
: Calculates the bounding box of the specified polygon.
void Draw_Line (Am_Style ls, int x1, int y1, int x2, int y2, Am_Draw_Function f = Am_DRAW_COPY)
: Draws a single straight line with style ls
.
void Draw_Lines (Am_Style ls, Am_Style fs, Am_Point_List pl, Am_Draw_Function f = Am_DRAW_COPY)
: Draws an optionally filled polygon.
void Draw_2_Lines (Am_Style ls, Am_Style fs, int x1, int y1, int x2, int y2, int x3, int y3, Am_Draw_Function f = Am_DRAW_COPY)
: This is provided for more efficient drawing of an optionally filled polygon with exactly 2 lines.
void Draw_3_Lines (Am_Style ls, Am_Style fs, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, Am_Draw_Function f = Am_DRAW_COPY)
: This is provided for more efficient drawing of an optionally filled polygon with exactly 3 lines.
void Draw_Rectangle (Am_Style ls, Am_Style fs, int left, int top, int width, int height, Am_Draw_Function f = Am_DRAW_COPY )
: This draws an optionally filled rectangle.
void Draw_Roundtangle (Am_Style ls, Am_Style fs, int left, int top, int width, int height, unsigned short x_radius, unsigned short y_radius, Am_Draw_Function f = Am_DRAW_COPY)
: This draws a rectangle with rounded corners.
void Draw_Text (Am_Style ls, const char *s, int str_len, Am_Font Am_font, int left, int top, Am_Draw_Function f = Am_DRAW_COPY, Am_Style fs = Am_No_Style, bool invert = false)
: This draws a single line of text in the specified font. ls
specifies the style of the text, and fs
specifies the style of the rectangular region behind the text. If fs
is Am_No_Style
, the background is transparent.
Am_Input_Event_Handlers
. You can specify one instance of this class for each of the drawonables in your application. The event handler methods take the drawonable and event information as parameters. For example, each time the user hits a keyboard key over a certain window, that window's event handlers are retreived, and, the
Input_Event_Notify
member function is called, with information about what key was pressed, which drawonable received the keypress, and where the mouse was positioned within the window when the key was pressed.Opal defines standard event handlers, so anyone programming at the Opal layer or above will not have to provide these event handlers. Instead, you should use an interactor for event handling, or create a new interactor if none of the available interactors is appropriate. To add or change the functionality of the standard opal event handlers, derive a new class from the C++ class
Am_Standard_Opal_Handlers
(exported in opal_advanced.h
), and replace some of the virtual functions with your own event handlers.
Am_Input_Event_Handlers
is defined as:
class Am_Input_Event_Handlers {
public:
virtual void Iconify_Notify (Am_Drawonable* draw, bool iconified) = 0;
virtual void Frame_Resize_Notify (Am_Drawonable* draw, int left,
int top, int right, int bottom) = 0;
virtual void Destroy_Notify (Am_Drawonable *draw) = 0;
virtual void Configure_Notify (Am_Drawonable *draw, int left, int top,
int width, int height) = 0;
virtual void Exposure_Notify (Am_Drawonable *draw,
int left, int top,
int width, int height) = 0;
virtual void Input_Event_Notify (Am_Drawonable *draw,
Am_Input_Event *ev)=0;
};The member functions are:
Iconify_Notify
: Called when the window is being iconified or de-iconified. The parameter iconified
is true if the window is now iconified, and false if it was just de-iconified.
Frame_Resize_Notify
: Called whenever the window's border size changes (for example, if title bars are added or removed).
Destroy_Notify
: Called when the user requests that the window be destroyed. Note that window managers often don't actually destroy the windows, but rather call this routine to tell the programs to destroy the window.
Configure_Notify
: Called whenever the user changes the window's size or position.
Exposure_Notify
: Called when the window becomes uncovered and part of it needs to be redrawn. The rectangle specified by left
, top
, width
, and height
is the bounding box of the region that should be redrawn.
Input_Event_Notify
: Called for all input events from the keyboard and mouse. The Am_Input_Event
is described below.
void Set_Input_Dispatch_Functions (Am_Input_Event_Handlers* evh)
void Get_Input_Dispatch_Functions (Am_Input_Event_Handlers*& evh)
Input_Event_Notify
method is a C++ class containing the position of the mouse when the event occured, the drawonable of the event, a timestamp, and an Am_Input_Char
describing the event. Am_Input_Chars
are described in Chapter 5, Interactors and Command Objects for Handling Input.
class Am_Input_Event {
public:
Am_Input_Char input_char;
//the char and modifier bits; see idefs.h
int x;
int y;
Am_Drawonable *draw;
// Drawonable this event happened in
unsigned long time_stamp;
};
You can control which input events are generated for a drawonable using the following member functions of drawonables:
void Set_Enter_Leave (bool want_enter_leave_events()
: If you want Input_Event_Notify()
to be called when the mouse enters or leaves this drawonable, Set_Enter_Leave(true)
. The default is false
.
void Set_Want_Move (bool want_move_events):
If you want a window to receive move events, set this to true
. The default is false
.
void Set_Multi_Window (bool want_multi_window):
When an interactor should run over multiple windows, this method should be called on each window. Otherwise, the cursor is "reserved" for the original window the mouse is clicked in.
void Get_Window_Mask (bool& want_enter_leave_events, bool& want_move_events, bool& want_multi_window)
: This returns information about which input events a drawonable is receiving.
Am_Double_Click_Time
is the inter-click wait time in milliseconds. The default value is 250. If it is 0, then no double-click processing is done. On the Mac, Am_Double_Click_Time
is ignored. The global system click time is used instead. It is usually set from the Mouse Control Panel.
Am_Initialize
(which among other things, calls Get_Root_Drawonable
), then sets up a number of objects, and then calls Am_Main_Event_Loop
or Am_Do_Events
(Section 4.3.4). These routines then call a Gem level level routine where the events are actually processed. This routine is Am_Drawonable::Process_Event()
. An Gem-level programmer who wants to process events, but not use any of the higher-level Amulet operations like demons and Opal might use Am_Drawonable::Main_Loop
. This just repeatedly calls Am_Drawonable::Process_Event ()
. To stop any of the main loops, you can set the exported bool
called Am_Main_Loop_Go
to false.
The difference between
Process_Event
and Process_Immediate_Event
is that Process_Event
waits for the next event, and processes exactly one input event and all non-input events (like refresh and configure_notify events) before and after that input event before returning. For example: before after
xxxIyyyIzzz ---> Izzz
Process_Event
returns when it encounters a second input event or when the queue is emptyProcess_Immediate_Event
does not wait for an event, but processes the first event in the queue and all non-input events after it until an input event is seen. Process_Immedi-ate_Event
returns when it encounters an input event (excluding the case where the first event is an input event) or when the queue is empty.// Should Am_Drawonable::Main_Loop and Am_Main_Event_Loop keep running?
extern bool Am_Main_Loop_Go;
class Am_Drawonable {
public:
...
static void Main_Loop ();
static void Process_Event ();
static void Process_Immediate_Event ();
...
Am_Main_Event_Loop
uses Process_Event
, and Am_Do_Events
uses Process_Immediate_Event
.