From 0be30cdc5d25f85a7a0bbf3a2c2aeddae3d301d7 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 24 Feb 2009 20:39:34 +0000 Subject: SCI: Renamed gfx/gfx_operations.h to gfx/operations.h (matching the source file); moved include/sci_widgets.h to gfx/ (matching location of source file); renamed gfx/widgets.cpp to gfx/gfx_widgets.cpp (matching the header) svn-id: r38852 --- engines/sci/engine/kernel.cpp | 2 +- engines/sci/engine/kgraphics.cpp | 2 +- engines/sci/engine/kmenu.cpp | 2 +- engines/sci/engine/savegame.cfsml | 2 +- engines/sci/engine/savegame.cpp | 2 +- engines/sci/engine/scriptdebug.cpp | 2 +- engines/sci/gfx/gfx_operations.h | 682 ----------- engines/sci/gfx/gfx_state_internal.h | 2 +- engines/sci/gfx/gfx_widgets.cpp | 2154 ++++++++++++++++++++++++++++++++++ engines/sci/gfx/menubar.h | 2 +- engines/sci/gfx/operations.cpp | 2 +- engines/sci/gfx/operations.h | 682 +++++++++++ engines/sci/gfx/sci_widgets.cpp | 4 +- engines/sci/gfx/sci_widgets.h | 205 ++++ engines/sci/gfx/widgets.cpp | 2154 ---------------------------------- engines/sci/include/sci_widgets.h | 205 ---- engines/sci/module.mk | 2 +- engines/sci/scicore/sciconsole.h | 2 +- 18 files changed, 3054 insertions(+), 3054 deletions(-) delete mode 100644 engines/sci/gfx/gfx_operations.h create mode 100644 engines/sci/gfx/gfx_widgets.cpp create mode 100644 engines/sci/gfx/operations.h create mode 100644 engines/sci/gfx/sci_widgets.h delete mode 100644 engines/sci/gfx/widgets.cpp delete mode 100644 engines/sci/include/sci_widgets.h (limited to 'engines') diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 396d415d35..0263142d38 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -39,7 +39,7 @@ #include "sci/engine/kernel.h" #include "sci/include/sciresource.h" #include "sci/include/engine.h" -#include "sci/gfx/gfx_operations.h" +#include "sci/gfx/operations.h" #include "sci/engine/kernel_types.h" namespace Sci { diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index 2eb3372ea5..ef47e04ada 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -27,7 +27,7 @@ #include "sci/include/sciresource.h" #include "sci/include/engine.h" -#include "sci/include/sci_widgets.h" +#include "sci/gfx/sci_widgets.h" #include "sci/gfx/gfx_widgets.h" #include "sci/engine/sci_graphics.h" #include "sci/engine/kernel.h" diff --git a/engines/sci/engine/kmenu.cpp b/engines/sci/engine/kmenu.cpp index 8eac3fa270..be5b8b9c22 100644 --- a/engines/sci/engine/kmenu.cpp +++ b/engines/sci/engine/kmenu.cpp @@ -25,7 +25,7 @@ #include "sci/include/sciresource.h" #include "sci/include/engine.h" -#include "sci/include/sci_widgets.h" +#include "sci/gfx/sci_widgets.h" #include "sci/gfx/menubar.h" #include "sci/engine/kernel.h" diff --git a/engines/sci/engine/savegame.cfsml b/engines/sci/engine/savegame.cfsml index ff55fe0a55..088d5952e6 100644 --- a/engines/sci/engine/savegame.cfsml +++ b/engines/sci/engine/savegame.cfsml @@ -33,7 +33,7 @@ #include "common/stream.h" #include "common/system.h" #include "sci/sci_memory.h" -#include "sci/gfx/gfx_operations.h" +#include "sci/gfx/operations.h" #include "sci/gfx/menubar.h" #include "sci/sfx/sfx_engine.h" #include "sci/include/engine.h" diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index beff271865..eb47d76316 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -33,7 +33,7 @@ #include "common/stream.h" #include "common/system.h" #include "sci/sci_memory.h" -#include "sci/gfx/gfx_operations.h" +#include "sci/gfx/operations.h" #include "sci/gfx/menubar.h" #include "sci/sfx/sfx_engine.h" #include "sci/include/engine.h" diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index 2aee9f9fc4..26c8131a9f 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -34,7 +34,7 @@ #include "sci/engine/kernel.h" #include "sci/engine/kernel_types.h" #include "sci/include/sci_midi.h" -#include "sci/include/sci_widgets.h" +#include "sci/gfx/sci_widgets.h" #include "sci/sci.h" #include "sci/gfx/gfx_widgets.h" diff --git a/engines/sci/gfx/gfx_operations.h b/engines/sci/gfx/gfx_operations.h deleted file mode 100644 index d3cdedceac..0000000000 --- a/engines/sci/gfx/gfx_operations.h +++ /dev/null @@ -1,682 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/* Graphical operations, called from the widget state manager */ - -#ifndef SCI_GFX_GFX_OPERATIONS_H -#define SCI_GFX_GFX_OPERATIONS_H - -#include "sci/gfx/gfx_resmgr.h" -#include "sci/gfx/gfx_tools.h" -#include "sci/gfx/gfx_options.h" -#include "sci/gfx/gfx_system.h" -#include "sci/include/uinput.h" - -namespace Sci { - -#define GFXOP_NO_POINTER -1 - -/* Threshold in color index mode to differentiate between visible and non-visible stuff. -** GFXOP_ALPHA_THRESHOLD itself should be treated as non-visible. -*/ -#define GFXOP_ALPHA_THRESHOLD 0xff - -struct gfx_text_handle_t { - char *text; /* Copy of the actual text */ - - int lines_nr; - int line_height; - text_fragment_t *lines; /* Text offsets */ - gfx_bitmap_font_t *font; - gfx_pixmap_t **text_pixmaps; - - int width, height; - - int priority, control; - gfx_alignment_t halign, valign; -}; - -/* Unless individually stated otherwise, the following applies: -** All operations herein apply to the standard 320x200 coordinate system. -** All operations perform clipping relative to state->clip_zone. -*/ - -typedef enum { - GFX_BOX_SHADE_FLAT, - GFX_BOX_SHADE_RIGHT, - GFX_BOX_SHADE_LEFT, - GFX_BOX_SHADE_DOWN, - GFX_BOX_SHADE_UP -#if 0 - /* possible with alphaing, but there is no way to check for - ** alpha capability of gfx_driver->draw_filled_rect() yet - */ - , GFX_BOX_SHADE_RIGHT_DOWN, - GFX_BOX_SHADE_LEFT_DOWN, - GFX_BOX_SHADE_RIGHT_UP, - GFX_BOX_SHADE_LEFT_UP -#endif -} gfx_box_shade_t; - - -struct gfx_dirty_rect_t { - rect_t rect; - gfx_dirty_rect_t *next; -}; - - -struct gfx_input_event_t { - sci_event_t event; - gfx_input_event_t *next; -}; - -struct gfx_state_t { - int version; /* Interpreter version */ - - gfx_options_t *options; - - Common::Point pointer_pos; /* Mouse pointer coordinates */ - - rect_t clip_zone_unscaled; /* The current UNSCALED clipping zone */ - rect_t clip_zone; /* The current SCALED clipping zone; a cached scaled version of clip_zone_unscaled */ - - gfx_driver_t *driver; - gfx_pixmap_color_t *static_palette; /* Null for dynamic palettes */ - int static_palette_entries; - - int visible_map; - - gfx_resstate_t *resstate; /* Resource state */ - - gfx_pixmap_t *priority_map; /* back buffer priority map (unscaled) */ - gfx_pixmap_t *static_priority_map; /* static buffer priority map (unscaled) */ - gfx_pixmap_t *control_map; /* back buffer control map (only exists unscaled in the first place) */ - - - int mouse_pointer_visible; /* Whether the pointer is drawn right now */ - Common::Point old_pointer_draw_pos; /* Mouse pointer draw coordinates */ - rect_t pointer_bg_zone; /* old-pointer-draw-pos relative zone inside the pointer - ** pixmap that was drawn */ - - int mouse_pointer_in_hw; /* Current pointer is being handled in hardware */ - - gfx_pixmap_t *mouse_pointer; /* Only set when drawing the mouse manually */ - gfx_pixmap_t *mouse_pointer_bg; /* Background under the pointer */ - - int tag_mode; /* Set to 1 after a new pic is drawn and the resource manager - ** has tagged all resources. Reset after the next front buffer - ** update is done, when all resources that are still tagged are - ** flushed. */ - - int disable_dirty; /* Set to 1 to disable dirty rect accounting */ - - int pic_nr; /* Number of the current pic */ - int palette_nr; /* Palette number of the current pic */ - - gfx_input_event_t *events; - - gfx_pixmap_t *fullscreen_override; /* An optional override picture which must have unscaled - ** full-screen size, which overrides all other visibility, and - ** which is generally slow */ - - gfxr_pic_t *pic, *pic_unscaled; /* The background picture and its unscaled equivalent */ - - gfx_dirty_rect_t *dirty_rects; /* Dirty rectangles */ - - void *internal_state; /* Internal interpreter information */ - -}; - - -/**************************/ -/* Fundamental operations */ -/**************************/ - -int gfxop_init_default(gfx_state_t *state, gfx_options_t *options, void *misc_info); -/* Initializes a graphics mode suggested by the graphics driver -** Parameters: (gfx_state_ t *) state: The state to initialize in that mode -** (gfx_options_t *) options: Rendering options -** (void *) misc_info: Additional information for the interpreter -** part of the resource loader -** Returns : (int) GFX_OK on success, GFX_FATAL otherwise -*/ - -int gfxop_init(gfx_state_t *state, int xfact, int yfact, gfx_color_mode_t bpp, - gfx_options_t *options, void *misc_info); -/* Initializes a custom graphics mode -** Parameters: (gfx_state_t *) state: The state to initialize -** (int x int) xfact, yfact: Horizontal and vertical scale factors -** (gfx_color_mode_t) bpp: Bytes per pixel to initialize with, or -** 0 (GFX_COLOR_MODE_AUTO) to auto-detect -** (gfx_options_t *) options: Rendering options -** (void *) misc_info: Additional information for the interpreter -** part of the resource loader -** Returns : (int) GFX_OK on success, GFX_ERROR if that particular mode is -** unavailable, or GFX_FATAL if the graphics driver is unable -** to provide any useful graphics support -*/ - -int gfxop_set_parameter(gfx_state_t *state, char *attribute, char *value); -/* Sets a driver-specific parameter -** Parameters: (gfx_state_t *) state: The state, encapsulating the driver object to manipulate -** (char *) attribute: The attribute to set -** (char *) value: The value the attribute should be set to -** Returns : (int) GFX_OK on success, GFX_FATAL on fatal error conditions triggered -** by the command -*/ - -int gfxop_exit(gfx_state_t *state); -/* Deinitializes a currently active driver -** Parameters: (gfx_state_t *) state: The state encapsulating the driver in question -** Returns : (int) GFX_OK -*/ - -int gfxop_scan_bitmask(gfx_state_t *state, rect_t area, gfx_map_mask_t map); -/* Calculates a bit mask calculated from some pixels on the specified map -** Parameters: (gfx_state_t *) state: The state containing the pixels to scan -** (rect_t) area: The area to check -** (gfx_map_mask_t) map: The GFX_MASKed map(s) to test -** Returns : (int) An integer value where, for each 0<=i<=15, bit #i is set -** iff there exists a map for which the corresponding bit was set -** in the 'map' parameter and for which there exists a pixel within -** the specified area so that the pixel's lower 4 bits, interpreted -** as an integer value, equal i. -** (Short version: This is an implementation of "on_control()"). -*/ - -int gfxop_set_visible_map(gfx_state_t *state, gfx_map_mask_t map); -/* Sets the currently visible map -** Parameters: (gfx_state_t *) state: The state to modify -** (gfx_map_mask_t) map: The GFX_MASK to set -** Returns : (int) GFX_OK, or GFX_ERROR if map was invalid -** 'visible_map' can be any of GFX_MASK_VISUAL, GFX_MASK_PRIORITY and GFX_MASK_CONTROL; the appropriate -** map (as far as its contents are known to the graphics subsystem) is then subsequently drawn to the -** screen at each update. If this is set to anything other than GFX_MASK_VISUAL, slow full-screen updates -** are performed. Mostly useful for debugging. -** The screen needs to be updated for the changes to take effect. -*/ - -int gfxop_set_clip_zone(gfx_state_t *state, rect_t zone); -/* Sets a new clipping zone -** Parameters: (gfx_state_t *) state: The affected state -** (rect_t) zone: The new clipping zone -** Returns : (int) GFX_OK -*/ - -/******************************/ -/* Generic drawing operations */ -/******************************/ - -int gfxop_draw_line(gfx_state_t *state, - Common::Point start, Common::Point end, gfx_color_t color, - gfx_line_mode_t line_mode, gfx_line_style_t line_style); -/* Renders a clipped line to the back buffer -** Parameters: (gfx_state_t *) state: The state affected -** (Common::Point) start: Starting point of the line -** (Common::Point) end: End point of the line -** (gfx_color_t) color: The color to use for drawing -** (gfx_line_mode_t) line_mode: Any valid line mode to use -** (gfx_line_style_t) line_style: The line style to use -** Returns : (int) GFX_OK or GFX_FATAL -*/ - -int gfxop_draw_rectangle(gfx_state_t *state, rect_t rect, gfx_color_t color, gfx_line_mode_t line_mode, - gfx_line_style_t line_style); -/* Draws a non-filled rectangular box to the back buffer -** Parameters: (gfx_state_t *) state: The affected state -** (rect_t) rect: The rectangular area the box is drawn to -** (gfx_color_t) color: The color the box is to be drawn in -** (gfx_line_mode_t) line_mode: The line mode to use -** (gfx_line_style_t) line_style: The line style to use for the box -** Returns : (int) GFX_OK or GFX_FATAL -** Boxes drawn in thin lines will surround the minimal area described by rect. -*/ - -int gfxop_draw_box(gfx_state_t *state, rect_t box, gfx_color_t color1, gfx_color_t color2, - gfx_box_shade_t shade_type); -/* Draws a filled box to the back buffer -** Parameters: (gfx_state_t *) state: The affected state -** (rect_t) box: The area to draw to -** (gfx_color_t) color1: The primary color to use for drawing -** (gfx_color_t) color2: The secondary color to draw in -** (gfx_box_shade_t) shade_type: The shading system to use -** (e.g. GFX_BOX_SHADE_FLAT) -** Returns : (int) GFX_OK or GFX_FATAL -** The draw mask, control, and priority values are derived from color1. -*/ - -int gfxop_fill_box(gfx_state_t *state, rect_t box, gfx_color_t color); -/* Fills a box in the back buffer with a specific color -** Parameters: (gfx_state_t *) state: The state to draw to -** (rect_t) box: The box to fill -** (gfx_color_t) color: The color to use for filling -** Returns : (int) GFX_OK or GFX_FATAL -** This is a simple wrapper function for gfxop_draw_box -*/ - -int gfxop_clear_box(gfx_state_t *state, rect_t box); -/* Copies a box from the static buffer to the back buffer -** Parameters: (gfx_state_t *) state: The affected state -** (rect_t) box: The box to propagate from the static buffer -** Returns : (int) GFX_OK or GFX_FATAL -*/ - - -int gfxop_update(gfx_state_t *state); -/* Updates all dirty rectangles -** Parameters: (gfx_state_t) *state: The relevant state -** Returns : (int) GFX_OK or GFX_FATAL if reported by the driver -** In order to track dirty rectangles, they must be enabled in the options. -** This function instructs the resource manager to free all tagged data -** on certain occasions (see gfxop_new_pic). -*/ - - -int gfxop_update_box(gfx_state_t *state, rect_t box); -/* Propagates a box from the back buffer to the front (visible) buffer -** Parameters: (gfx_state_t *) state: The affected state -** (rect_t) box: The box to propagate to the front buffer -** Returns : (int) GFX_OK or GFX_FATAL -** This function instructs the resource manager to free all tagged data -** on certain occasions (see gfxop_new_pic). -** When called with dirty rectangle management enabled, it will automatically -** propagate all dirty rectangles as well, UNLESS dirty frame accounting has -** been disabled explicitly. -*/ - -int gfxop_enable_dirty_frames(gfx_state_t *state); -/* Enables dirty frame accounting -** Parameters: (gfx_state_t *) state: The state dirty frame accounting is to be enabled in -** Returns : (int) GFX_OK or GFX_ERROR if state was invalid -** Dirty frame accounting is enabled by default. -*/ - -int gfxop_disable_dirty_frames(gfx_state_t *state); -/* Disables dirty frame accounting -** Parameters: (gfx_state_t *) state: The state dirty frame accounting is to be disabled in -** Returns : (int) GFX_OK or GFX_ERROR if state was invalid -*/ - - -/********************/ -/* Color operations */ -/********************/ - -int gfxop_set_color(gfx_state_t *state, gfx_color_t *color, int r, int g, int b, int a, - int priority, int control); -/* Maps an r/g/b value to a color and sets a gfx_color_t structure -** Parameters: (gfx_state_t *) state: The current state -** (gfx_color_t *) color: Pointer to the structure to write to -** (int x int x int) r,g,b: The red/green/blue color intensity values -** of the result color (0x00 (minimum) to 0xff (max)) -** If any of these values is less than zero, the -** resulting color will not affect the visual map when -** used for drawing -** (int) a: The alpha (transparency) value, with 0x00 meaning absolutely -** opaque and 0xff meaning fully transparent. Alpha blending support -** is optional for drivers, so these are the only two values that -** are guaranteed to work as intended. Any value in between them -** must guarantee the following opaqueness: -** opaqueness(x-1) >= opaqueness(x) >= opaqueness (x+1) -** (i.e. ([0,255], less-transparent-than) must define a partial order) -** (int) priority: The priority to use for drawing, or -1 for none -** (int) control: The control to use for drawing, or -1 to disable drawing to the -** control map -** Returns : (int) GFX_OK or GFX_ERROR if state is invalid -** In palette mode, this may allocate a new color. Use gfxop_free_color() described below to -** free that color. -*/ - -int gfxop_set_system_color(gfx_state_t *state, gfx_color_t *color); -/* Designates a color as a 'system color' -** Parameters: (gfx_state_t *) state: The affected state -** (gfx_color_t *) color: The color to designate as a system color -** Returns : (int) GFX_OK or GFX_ERROR if state is invalid -** System colors are permanent colors that cannot be deallocated. As such, they must be used -** with caution. -*/ - -int gfxop_free_color(gfx_state_t *state, gfx_color_t *color); -/* Frees a color allocated by gfxop_set_color() -** Parmaeters: (gfx_state_t *) state: The state affected -** (gfx_color_t *) color: The color to de-allocate -** Returns : (int) GFX_OK or GFX_ERROR if state is invalid -** This function is a no-op in non-index mode, or if color is a system color. -*/ - - -/**********************/ -/* Pointer and IO ops */ -/**********************/ - -int gfxop_usleep(gfx_state_t *state, long usecs); -/* Suspends program execution for the specified amount of microseconds -** Parameters: (gfx_state_t *) state: The state affected -** (long) usecs: The amount of microseconds to wait -** Returns : (int) GFX_OK or GFX_ERROR -** The mouse pointer will be redrawn continually, if applicable -*/ - -int gfxop_set_pointer_cursor(gfx_state_t *state, int nr); -/* Sets the mouse pointer to a cursor resource -** Parameters: (gfx_state_t *) state: The affected state -** (int) nr: Number of the cursor resource to use -** Returns : (int) GFX_OK, GFX_ERROR if the resource did not -** exist and was not GFXOP_NO_POINTER, or GFX_FATAL on -** fatal error conditions. -** Use nr = GFX_NO_POINTER to disable the mouse pointer (default). -*/ - -int gfxop_set_pointer_view(gfx_state_t *state, int nr, int loop, int cel, Common::Point *hotspot); -/* Sets the mouse pointer to a view resource -** Parameters: (gfx_state_t *) state: The affected state -** (int) nr: Number of the view resource to use -** (int) loop: View loop to use -** (int) cel: View cel to use -** (Common::Point *) hotspot: Manually set hotspot to use, or NULL for default. -** Returns : (int) GFX_OK or GFX_FATAL -** Use gfxop_set_pointer_cursor(state, GFXOP_NO_POINTER) to disable the -** pointer. -*/ - -int gfxop_set_pointer_position(gfx_state_t *state, Common::Point pos); -/* Teleports the mouse pointer to a specific position -** Parameters: (gfx_state_t *) state: The state the pointer is in -** (Common::Point) pos: The position to teleport it to -** Returns : (int) Any error code or GFX_OK -** Depending on the graphics driver, this operation may be without -** any effect -*/ - -sci_event_t gfxop_get_event(gfx_state_t *state, unsigned int mask); -/* Retreives the next input event from the driver -** Parameters: (gfx_state_t *) state: The affected state -** (int) mask: The event mask to poll from (see uinput.h) -** Returns : (sci_event_t) The next event in the driver's event queue, or -** a NONE event if no event matching the mask was found. -*/ - - -/*******************/ -/* View operations */ -/*******************/ - -int gfxop_lookup_view_get_loops(gfx_state_t *state, int nr); -/* Determines the number of loops associated with a view -** Parameters: (gfx_state_t *) state: The state to use -** (int) nr: Number of the view to investigate -** Returns : (int) The number of loops, or GFX_ERROR if the view didn't exist -*/ - -int gfxop_lookup_view_get_cels(gfx_state_t *state, int nr, int loop); -/* Determines the number of cels associated stored in a loop -** Parameters: (gfx_state_t *) state: The state to look up in -** (int) nr: Number of the view to look up in -** (int) loop: Number of the loop the number of cels of -** are to be investigated -** Returns : (int) The number of cels in that loop, or GFX_ERROR if either -** the view or the loop didn't exist -*/ - -int gfxop_check_cel(gfx_state_t *state, int nr, int *loop, int *cel); -/* Clips the view/loop/cel position of a cel -** Parameters: (gfx_state_t *) state: The state to use -** (int) nr: Number of the view to use -** (int *) loop: Pointer to the variable storing the loop -** number to verify -** (int *) cel: Pointer to the variable storing the cel -** number to check -** Returns : (int) GFX_OK or GFX_ERROR if the view didn't exist -** *loop is clipped first, then *cel. The resulting setup will be a valid -** view configuration. -*/ - -int gfxop_overflow_cel(gfx_state_t *state, int nr, int *loop, int *cel); -/* Resets loop/cel values to zero if they have become invalid -** Parameters: (gfx_state_t *) state: The state to use -** (int) nr: Number of the view to use -** (int *) loop: Pointer to the variable storing the loop -** number to verify -** (int *) cel: Pointer to the variable storing the cel -** number to check -** Returns : (int) GFX_OK or GFX_ERROR if the view didn't exist -** *loop is clipped first, then *cel. The resulting setup will be a valid -** view configuration. -*/ - -int gfxop_get_cel_parameters(gfx_state_t *state, int nr, int loop, int cel, - int *width, int *height, Common::Point *offset); -/* Retreives the width and height of a cel -** Parameters: (gfx_state_t *) state: The state to use -** (int) nr: Number of the view -** (int) loop: Loop number to examine -** (int) cel: The cel (inside the loop) to look up -** (int *) width: The variable the width will be stored in -** (int *) height: The variable the height will be stored in -** (Common::Point *) offset: The variable the cel's x/y offset will be stored in -** Returns : (int) GFX_OK if the lookup succeeded, GFX_ERROR if the nr/loop/cel -** combination was invalid -*/ - -int gfxop_draw_cel(gfx_state_t *state, int nr, int loop, int cel, Common::Point pos, - gfx_color_t color, int palette); -/* Draws (part of) a cel to the back buffer -** Parameters: (gfx_state_t *) state: The state encapsulating the driver to draw with -** (int) nr: Number of the view to draw -** (int) loop: Loop of the cel to draw -** (int) cel: The cel number of the cel to draw -** (Common::Point) pos: The positino the cel is to be drawn to -** (gfx_color_t color): The priority and control values to use for drawing -** (int) palette: The palette to use -** Returns : (int) GFX_OK or GFX_FATAL -*/ - - -int gfxop_draw_cel_static(gfx_state_t *state, int nr, int loop, int cel, Common::Point pos, - gfx_color_t color, int palette); -/* Draws a cel to the static buffer; no clipping is performed -** Parameters: (gfx_state_t *) state: The state encapsulating the driver to draw with -** (int) nr: Number of the view to draw -** (int) loop: Loop of the cel to draw -** (int) cel: The cel number of the cel to draw -** (Common::Point) pos: The positino the cel is to be drawn to -** (gfx_color_t color): The priority and control values to use for drawing -** (int) palette: The palette to use -** Returns : (int) GFX_OK or GFX_FATAL -** Let me repeat, no clipping (except for the display borders) is performed. -*/ - - -int gfxop_draw_cel_static_clipped(gfx_state_t *state, int nr, int loop, int cel, Common::Point pos, - gfx_color_t color, int palette); -/* Draws (part of) a clipped cel to the static buffer -** Parameters: (gfx_state_t *) state: The state encapsulating the driver to draw with -** (int) nr: Number of the view to draw -** (int) loop: Loop of the cel to draw -** (int) cel: The cel number of the cel to draw -** (Common::Point) pos: The positino the cel is to be drawn to -** (gfx_color_t color): The priority and control values to use for drawing -** (int) palette: The palette to use -** Returns : (int) GFX_OK or GFX_FATAL -** This function does clip. -*/ - - -/******************/ -/* Pic operations */ -/******************/ -/* These operations are exempt from clipping */ - -int gfxop_new_pic(gfx_state_t *state, int nr, int flags, int default_palette); -/* Draws a pic and writes it over the static buffer -** Parameters: (gfx_state_t *) state: The state affected -** (int) nr: Number of the pic to draw -** (int) flags: Interpreter-dependant flags to use for drawing -** (int) default_palette: The default palette for drawing -** Returns : (int) GFX_OK or GFX_FATAL -** This function instructs the resource manager to tag all data as "unused". -** See the resource manager tag functions for a full description. -*/ - -void *gfxop_get_pic_metainfo(gfx_state_t *state); -/* Retreives all meta-information assigned to the current pic -** Parameters: (gfx_state_t *) state: The state affected -** Returns : (void *) NULL if the pic doesn't exist or has no meta-information, -** the meta-info otherwise -** This meta-information is referred to as 'internal data' in the pic code -*/ - -int gfxop_add_to_pic(gfx_state_t *state, int nr, int flags, int default_palette); -/* Adds a pic to the static buffer -** Parameters: (gfx_state_t *) state: The state affected -** (int) nr: Number of the pic to add -** (int) flags: Interpreter-dependant flags to use for drawing -** (int) default_palette: The default palette for drawing -** Returns : (int) GFX_OK or GFX_FATAL -*/ - - - - -/*******************/ -/* Text operations */ -/*******************/ - - -int gfxop_get_font_height(gfx_state_t *state, int font_nr); -/* Returns the fixed line height for one specified font -** Parameters: (gfx_state_t *) state: The state to work on -** (int) font_nr: Number of the font to inspect -** Returns : (int) GFX_ERROR, GFX_FATAL, or the font line height -*/ - -int gfxop_get_text_params(gfx_state_t *state, int font_nr, const char *text, - int maxwidth, int *width, int *height, int flags, - int *lines_nr, int *lineheight, int *lastline_width); -/* Calculates the width and height of a specified text in a specified font -** Parameters: (gfx_state_t *) state: The state to use -** (int) font_nr: Font number to use for the calculation -** (const char *) text: The text to examine -** (int) flags: ORred GFXR_FONT_FLAGs -** (int) maxwidth: The maximum pixel width to allow for the text -** Returns : (int) GFX_OK or GFX_ERROR if the font didn't exist -** (int) *width: The resulting width -** (int) *height: The resulting height -** (int) *lines_nr: Number of lines used in the text -** (int) *lineheight: Pixel height (SCI scale) of each text line -** (int) *lastline_wdith: Pixel offset (SCI scale) of the space -** after the last character in the last line -*/ - -gfx_text_handle_t *gfxop_new_text(gfx_state_t *state, int font_nr, char *text, int maxwidth, - gfx_alignment_t halign, gfx_alignment_t valign, gfx_color_t color1, - gfx_color_t color2, gfx_color_t bg_color, int flags); -/* Generates a new text handle that can be used to draw any text -** Parameters: (gfx_state_t *) state: The state to use -** (int) font_nr: Font number to use for the calculation -** (char *) text: The text to examine -** (int) maxwidth: The maximum pixel width to allow for the text -** (gfx_alignment_t) halign: The horizontal text alignment -** (gfx_alignment_t) valign: The vertical text alignment -** (gfx_color_t x gfx_color_t) color1, color2: The text's foreground colors -** (the function will dither between those two) -** (gfx_color_t) bg_color: The background color -** (int) flags: ORred GFXR_FONT_FLAGs -** Returns : (gfx_text_handle_t *) A newly allocated gfx_text_handle_t, or -** NULL if font_nr was invalid -** The control and priority values for the text will be extracted from color1. -** Note that the colors must have been allocated properly, or the text may display in -** incorrect colors. -*/ - -int gfxop_free_text(gfx_state_t *state, gfx_text_handle_t *handle); -/* Frees a previously allocated text handle and all related resources -** Parameters: (gfx_state_t *) state: The state to use -** (gfx_text_handle_t *) handle: The handle to free -** Returns : (int) GFX_OK -*/ - -int gfxop_draw_text(gfx_state_t *state, gfx_text_handle_t *handle, rect_t zone); -/* Draws text stored in a text handle -** Parameters: (gfx_state_t *) state: The target state -** (gfx_text_handle_t *) handle: The text handle to use for drawing -** (rect_t) zone: The rectangular box to draw to. In combination with -** halign and valign, this defines where the text is -** drawn to. -** Returns : (int) GFX_OK or GFX_FATAL -*/ - - -/****************************/ -/* Manual pixmap operations */ -/****************************/ - -gfx_pixmap_t *gfxop_grab_pixmap(gfx_state_t *state, rect_t area); -/* Grabs a screen section from the back buffer and stores it in a pixmap -** Parameters: (gfx_state_t *) state: The affected state -** (rect_t) area: The area to grab -** Returns : (gfx_pixmap_t *) A result pixmap, or NULL on error -** Obviously, this only affects the visual map -*/ - -int gfxop_draw_pixmap(gfx_state_t *state, gfx_pixmap_t *pxm, rect_t zone, Common::Point pos); -/* Draws part of a pixmap to the screen -** Parameters: (gfx_state_t *) state: The affected state -** (gfx_pixmap_t *) pxm: The pixmap to draw -** (rect_t) zone: The segment of the pixmap to draw -** (Common::Point) pos: The position the pixmap should be drawn to -** Returns : (int) GFX_OK or any error code -*/ - -int gfxop_free_pixmap(gfx_state_t *state, gfx_pixmap_t *pxm); -/* Frees a pixmap returned by gfxop_grab_pixmap() -** Parameters: (gfx_state_t *) state: The affected state -** (gfx_pixmap_t *) pxm: The pixmap to free -** Returns : (int) GFX_OK, or GFX_ERROR if the state was invalid -*/ - -/******************************/ -/* Dirty rectangle operations */ -/******************************/ - -gfx_dirty_rect_t *gfxdr_add_dirty(gfx_dirty_rect_t *base, rect_t box, int strategy); -/* Adds a dirty rectangle to 'base' according to a strategy -** Parameters: (gfx_dirty_rect_t *) base: The base rectangle to add to, or NULL -** (rect_t) box: The dirty frame to add -** (int) strategy: The dirty frame heuristic to use (see gfx_options.h) -** Returns : (gfx_dirty_rect_t *) an appropriate singly-linked dirty rectangle -** result cluster -*/ - -int _gfxop_clip(rect_t *rect, rect_t clipzone); -/* Clips a rectangle against another one -** Parameters: (rect_t *) rect: The rectangle to clip -** (rect_t) clipzone: The outer bounds rect must be in -** Reuturns : (int) 1 if rect is empty now, 0 otherwise -*/ - -} // End of namespace Sci - -#endif // SCI_GFX_GFX_OPERATIONS_H diff --git a/engines/sci/gfx/gfx_state_internal.h b/engines/sci/gfx/gfx_state_internal.h index b5be874051..abce1fbae2 100644 --- a/engines/sci/gfx/gfx_state_internal.h +++ b/engines/sci/gfx/gfx_state_internal.h @@ -28,7 +28,7 @@ #include "sci/gfx/gfx_tools.h" #include "sci/gfx/gfx_options.h" -#include "sci/gfx/gfx_operations.h" +#include "sci/gfx/operations.h" #include "sci/gfx/gfx_resmgr.h" #include "sci/gfx/gfx_system.h" diff --git a/engines/sci/gfx/gfx_widgets.cpp b/engines/sci/gfx/gfx_widgets.cpp new file mode 100644 index 0000000000..02bf37b314 --- /dev/null +++ b/engines/sci/gfx/gfx_widgets.cpp @@ -0,0 +1,2154 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sci/sci_memory.h" +#include "sci/gfx/gfx_widgets.h" + +namespace Sci { + +#undef GFXW_DEBUG_DIRTY // Enable to debug dirty rectangle propagation (writes to stderr) + +#ifdef GFXW_DEBUG_DIRTY +# define DDIRTY fprintf(stderr, "%s:%5d| ", __FILE__, __LINE__); fprintf +#else +# define DDIRTY if (0) fprintf +#endif + +Common::Point gfxw_point_zero(0, 0); + +#define MAX_SERIAL_NUMBER 0x7fffffff +static int widget_serial_number_counter = 0x10000; // Avoid confusion with IDs + +#ifdef GFXW_DEBUG_WIDGETS + +gfxw_widget_t *debug_widgets[GFXW_DEBUG_WIDGETS]; +int debug_widget_pos = 0; + +static void _gfxw_debug_add_widget(gfxw_widget_t *widget) { + if (debug_widget_pos == GFXW_DEBUG_WIDGETS) { + GFXERROR("WIDGET DEBUG: Allocated the maximum number of %d widgets- Aborting!\n", GFXW_DEBUG_WIDGETS); + BREAKPOINT(); + } + debug_widgets[debug_widget_pos++] = widget; +} + +static void _gfxw_debug_remove_widget(gfxw_widget_t *widget) { + int i; + int found = 0; + for (i = 0; i < debug_widget_pos; i++) { + if (debug_widgets[i] == widget) { + memmove(debug_widgets + i, debug_widgets + i + 1, (sizeof(gfxw_widget_t *)) * (debug_widget_pos - i - 1)); + debug_widgets[debug_widget_pos--] = NULL; + found++; + } + } + + if (found > 1) { + GFXERROR("While removing widget: Found it %d times!\n", found); + BREAKPOINT(); + } + + if (found == 0) { + GFXERROR("Attempted removal of unregistered widget!\n"); + BREAKPOINT(); + } +} +#else // !GFXW_DEBUG_WIDGETS +#define _gfxw_debug_add_widget(a) +#define _gfxw_debug_remove_widget(a) +#endif + + +static inline void indent(int indentation) { + int i; + for (i = 0; i < indentation; i++) + sciprintf(" "); +} + +static void _gfxw_print_widget(gfxw_widget_t *widget, int indentation) { + unsigned int i; + char flags_list[] = "VOCDTMI"; + + indent(indentation); + + if (widget->magic == GFXW_MAGIC_VALID) { + if (widget->visual) + sciprintf("v "); + else + sciprintf("NoVis "); + } else if (widget->magic == GFXW_MAGIC_INVALID) + sciprintf("INVALID "); + + sciprintf("S%08x", widget->serial); + + if (widget->ID != GFXW_NO_ID) { + sciprintf("#%x", widget->ID); + + if (widget->subID != GFXW_NO_ID) + sciprintf(":%x ", widget->subID); + else + sciprintf(" "); + } + + sciprintf("[(%d,%d)(%dx%d)]", widget->bounds.x, widget->bounds.y, widget->bounds.xl, widget->bounds.yl); + + for (i = 0; i < strlen(flags_list); i++) + if (widget->flags & (1 << i)) + sciprintf("%c", flags_list[i]); + + sciprintf(" "); +} + +static int _gfxwop_print_empty(gfxw_widget_t *widget, int indentation) { + _gfxw_print_widget(widget, indentation); + sciprintf("", widget->type); + + return 0; +} + +gfxw_widget_t * _gfxw_new_widget(int size, gfxw_widget_type_t type) { + gfxw_widget_t *widget = (gfxw_widget_t*)sci_malloc(size); +#ifdef SATISFY_PURIFY + memset(widget, 0, size); +#endif + + widget->magic = GFXW_MAGIC_VALID; + widget->parent = NULL; + widget->visual = NULL; + widget->next = NULL; + widget->type = type; + widget->bounds = gfx_rect(0, 0, 0, 0); + widget->flags = GFXW_FLAG_DIRTY; + widget->ID = GFXW_NO_ID; + widget->subID = GFXW_NO_ID; + widget->serial = widget_serial_number_counter++; + widget->widget_priority = -1; + + widget_serial_number_counter &= MAX_SERIAL_NUMBER; + + widget->draw = NULL; + widget->widfree = NULL; + widget->tag = NULL; + widget->print = _gfxwop_print_empty; + widget->should_replace = NULL; + widget->compare_to = widget->equals = widget->superarea_of = NULL; + + _gfxw_debug_add_widget(widget); + + return widget; +} + +static inline int verify_widget(gfxw_widget_t *widget) { + if (!widget) { + GFXERROR("Attempt to use NULL widget\n"); +#ifdef GFXW_DEBUG_WIDGETS + BREAKPOINT(); +#endif + return 1; + } else if (widget->magic != GFXW_MAGIC_VALID) { + if (widget->magic == GFXW_MAGIC_INVALID) { + GFXERROR("Attempt to use invalidated widget\n"); + } else { + GFXERROR("Attempt to use non-widget\n"); + } +#ifdef GFXW_DEBUG_WIDGETS + BREAKPOINT(); +#endif + return 1; + } + return 0; +} + +#define VERIFY_WIDGET(w) \ + if (verify_widget((gfxw_widget_t *)(w))) { GFXERROR("Error occured while validating widget\n"); } + +static void _gfxw_unallocate_widget(gfx_state_t *state, gfxw_widget_t *widget) { + if (GFXW_IS_TEXT(widget)) { + gfxw_text_t *text = (gfxw_text_t *) widget; + + if (text->text_handle) { + if (!state) { + GFXERROR("Attempt to free text without supplying mode to free it from!\n"); + BREAKPOINT(); + } else { + gfxop_free_text(state, text->text_handle); + text->text_handle = NULL; + } + } + } + + widget->magic = GFXW_MAGIC_INVALID; + free(widget); + _gfxw_debug_remove_widget(widget); +} + +#define GFX_ASSERT(_x) \ +{ \ + int retval = (_x); \ + if (retval == GFX_ERROR) { \ + GFXERROR("Error occured while drawing widget!\n"); \ + return 1; \ + } else if (retval == GFX_FATAL) { \ + error("Fatal error occured while drawing widget!\nGraphics state invalid; aborting program..."); \ + } \ +} + +//********** Widgets ************* + +// Base class operations and common stuff + +// Assertion for drawing +#define DRAW_ASSERT(widget, exp_type) \ + if (!(widget)) { \ + sciprintf("L%d: NULL widget", __LINE__); \ + return 1; \ + } \ + if (!(widget)->print) { \ + sciprintf("L%d: Widget of type %d does not have print function", __LINE__, (widget)->type); \ + } \ + if ((widget)->type != (exp_type)) { \ + sciprintf("L%d: Error in widget: Expected type " # exp_type "(%d) but got %d\n", __LINE__, exp_type, (widget)->type); \ + sciprintf("Erroneous widget: "); \ + widget->print(widget, 4); \ + sciprintf("\n"); \ + return 1; \ + } \ + if (!(widget->flags & GFXW_FLAG_VISIBLE)) \ + return 0; \ + if (!(widget->type == GFXW_VISUAL || widget->visual)) { \ + sciprintf("L%d: Error while drawing widget: Widget has no visual\n", __LINE__); \ + sciprintf("Erroneous widget: "); \ + widget->print(widget, 1); \ + sciprintf("\n"); \ + return 1; \ + } + +static inline int _color_equals(gfx_color_t a, gfx_color_t b) { + if (a.mask != b.mask) + return 0; + + if (a.mask & GFX_MASK_VISUAL) { + if (a.visual.r != b.visual.r || a.visual.g != b.visual.g || a.visual.b != b.visual.b || a.alpha != b.alpha) + return 0; + } + + if (a.mask & GFX_MASK_PRIORITY) + if (a.priority != b.priority) + return 0; + + if (a.mask & GFX_MASK_CONTROL) + if (a.control != b.control) + return 0; + + return 1; +} + +static int _gfxwop_basic_set_visual(gfxw_widget_t *widget, gfxw_visual_t *visual) { + widget->visual = visual; + + if (widget->parent) { + DDIRTY(stderr, "basic_set_visual: DOWNWARDS rel(%d,%d,%d,%d, 1)\n", GFX_PRINT_RECT(widget->bounds)); + widget->parent->add_dirty_rel(widget->parent, widget->bounds, 1); + } + + return 0; +} + +static int _gfxwop_basic_should_replace(gfxw_widget_t *widget, gfxw_widget_t *other) { + return 0; +} + +static inline void _gfxw_set_ops(gfxw_widget_t *widget, gfxw_point_op *draw, gfxw_op *free, gfxw_op *tag, gfxw_op_int *print, + gfxw_bin_op *compare_to, gfxw_bin_op *equals, gfxw_bin_op *superarea_of) { + widget->draw = draw; + widget->widfree = free; + widget->tag = tag; + widget->print = print; + widget->compare_to = compare_to; + widget->equals = equals; + widget->superarea_of = superarea_of; + + widget->should_replace = _gfxwop_basic_should_replace; + widget->set_visual = _gfxwop_basic_set_visual; +} + +void gfxw_remove_widget_from_container(gfxw_container_t *container, gfxw_widget_t *widget) { + gfxw_widget_t **seekerp; + + if (!container) { + GFXERROR("Attempt to remove widget from NULL container!\n"); + BREAKPOINT(); + } + + seekerp = &(container->contents); + + if (GFXW_IS_LIST(widget) && GFXW_IS_PORT(container)) { + gfxw_port_t *port = (gfxw_port_t *) container; + if (port->decorations == (gfxw_list_t *) widget) { + port->decorations = NULL; + return; + } + } + + while (*seekerp && *seekerp != widget) + seekerp = &((*seekerp)->next); + + if (!*seekerp) { + GFXERROR("Internal error: Attempt to remove widget from container it was not contained in!\n"); + sciprintf("Widget:"); + widget->print(GFXW(widget), 1); + sciprintf("Container:"); + widget->print(GFXW(container), 1); + BREAKPOINT(); + return; + } + + if (container->nextpp == &(widget->next)) + container->nextpp = seekerp; + + *seekerp = widget->next; // Remove it + widget->parent = NULL; + widget->next = NULL; +} + +static int _gfxwop_basic_free(gfxw_widget_t *widget) { + gfxw_visual_t *visual = widget->visual; + gfx_state_t *state = (visual) ? visual->gfx_state : NULL; + + DDIRTY(stderr, "BASIC-FREE: SomeAddDirty\n"); + + if (widget->parent) { + if (GFXW_IS_CONTAINER(widget)) + widget->parent->add_dirty_abs(widget->parent, widget->bounds, 1); + else + widget->parent->add_dirty_rel(widget->parent, widget->bounds, 1); + + gfxw_remove_widget_from_container(widget->parent, widget); + } + + _gfxw_unallocate_widget(state, widget); + + return 0; +} + +static int _gfxwop_basic_tag(gfxw_widget_t *widget) { + widget->flags |= GFXW_FLAG_TAGGED; + + return 0; +} + +static int _gfxwop_basic_compare_to(gfxw_widget_t *widget, gfxw_widget_t *other) { + return 1; +} + +static int _gfxwop_basic_equals(gfxw_widget_t *widget, gfxw_widget_t *other) { + return 0; +} + +static int _gfxwop_basic_superarea_of(gfxw_widget_t *widget, gfxw_widget_t *other) { + return (widget == other); +} + +//*** Boxes *** + +static inline rect_t _move_rect(rect_t rect, Common::Point point) { + return gfx_rect(rect.x + point.x, rect.y + point.y, rect.xl, rect.yl); +} + +static inline void _split_rect(rect_t rect, Common::Point *p1, Common::Point *p2) { + p1->x = rect.x; + p1->y = rect.y; + p2->x = rect.x + rect.xl; + p2->y = rect.y + rect.yl; +} + +static inline Common::Point _move_point(rect_t rect, Common::Point point) { + return Common::Point(rect.x + point.x, rect.y + point.y); +} + +static int _gfxwop_box_draw(gfxw_widget_t *widget, Common::Point pos) { + gfxw_box_t *box = (gfxw_box_t *) widget; + DRAW_ASSERT(widget, GFXW_BOX); + GFX_ASSERT(gfxop_draw_box(box->visual->gfx_state, _move_rect(box->bounds, pos), box->color1, box->color2, box->shade_type)); + + return 0; +} + +static int _gfxwop_box_print(gfxw_widget_t *widget, int indentation) { + _gfxw_print_widget(widget, indentation); + sciprintf("BOX"); + return 0; +} + +static int _gfxwop_box_superarea_of(gfxw_widget_t *widget, gfxw_widget_t *other) { + gfxw_box_t *box = (gfxw_box_t *) widget; + + if (box->color1.alpha) + return 0; + + if (box->shade_type != GFX_BOX_SHADE_FLAT && box->color2.alpha) + return 0; + + if (!gfx_rect_subset(other->bounds, box->bounds)) + return 0; + + return 1; +} + +static int _gfxwop_box_equals(gfxw_widget_t *widget, gfxw_widget_t *other) { + gfxw_box_t *wbox = (gfxw_box_t *)widget, *obox; + if (other->type != GFXW_BOX) + return 0; + + obox = (gfxw_box_t *) other; + + if (!gfx_rect_equals(wbox->bounds, obox->bounds)) + return 0; + + if (!_color_equals(wbox->color1, obox->color1)) + return 0; + + if (wbox->shade_type != obox->shade_type) + return 0; + + if (wbox->shade_type != GFX_BOX_SHADE_FLAT + && _color_equals(wbox->color2, obox->color2)) + return 0; + + return 1; +} + +void _gfxw_set_ops_BOX(gfxw_widget_t *widget) { + _gfxw_set_ops(GFXW(widget), _gfxwop_box_draw, _gfxwop_basic_free, _gfxwop_basic_tag, _gfxwop_box_print, + _gfxwop_basic_compare_to, _gfxwop_box_equals, _gfxwop_box_superarea_of); +} + +static inline int _gfxw_color_get_priority(gfx_color_t color) { + return (color.mask & GFX_MASK_PRIORITY) ? color.priority : -1; +} + +gfxw_box_t *gfxw_new_box(gfx_state_t *state, rect_t area, gfx_color_t color1, gfx_color_t color2, gfx_box_shade_t shade_type) { + gfxw_box_t *widget = (gfxw_box_t *)_gfxw_new_widget(sizeof(gfxw_box_t), GFXW_BOX); + + widget->widget_priority = _gfxw_color_get_priority(color1); + widget->bounds = area; + widget->color1 = color1; + widget->color2 = color2; + widget->shade_type = shade_type; + + widget->flags |= GFXW_FLAG_VISIBLE; + + if ((color1.mask & GFX_MASK_VISUAL) && ((state && (state->driver->mode->palette)) || (!color1.alpha && !color2.alpha))) + widget->flags |= GFXW_FLAG_OPAQUE; + + _gfxw_set_ops_BOX(GFXW(widget)); + + return widget; +} + +static inline gfxw_primitive_t *_gfxw_new_primitive(rect_t area, gfx_color_t color, gfx_line_mode_t mode, + gfx_line_style_t style, gfxw_widget_type_t type) { + gfxw_primitive_t *widget = (gfxw_primitive_t *)_gfxw_new_widget(sizeof(gfxw_primitive_t), type); + + widget->widget_priority = _gfxw_color_get_priority(color); + widget->bounds = area; + widget->color = color; + widget->line_mode = mode; + widget->line_style = style; + + widget->flags |= GFXW_FLAG_VISIBLE; + return widget; +} + +//*** Rectangles *** + +static int _gfxwop_primitive_equals(gfxw_widget_t *widget, gfxw_widget_t *other) { + gfxw_primitive_t *wprim = (gfxw_primitive_t *) widget, *oprim; + if (widget->type != other->type) + return 0; + + oprim = (gfxw_primitive_t *) other; + + if (!gfx_rect_equals(wprim->bounds, oprim->bounds)) + return 0; + + if (!_color_equals(wprim->color, oprim->color)) + return 0; + + if (wprim->line_mode != oprim->line_mode) + return 0; + + if (wprim->line_style != oprim->line_style) + return 0; + + return 1; +} + +static int _gfxwop_rect_draw(gfxw_widget_t *widget, Common::Point pos) { + gfxw_primitive_t *rect = (gfxw_primitive_t *) widget; + DRAW_ASSERT(widget, GFXW_RECT); + + GFX_ASSERT(gfxop_draw_rectangle(rect->visual->gfx_state, gfx_rect(rect->bounds.x + pos.x, rect->bounds.y + pos.y, + rect->bounds.xl - 1, rect->bounds.yl - 1), rect->color, rect->line_mode, rect->line_style)); + return 0; +} + +static int _gfxwop_rect_print(gfxw_widget_t *rect, int indentation) { + _gfxw_print_widget(GFXW(rect), indentation); + sciprintf("RECT"); + + return 0; +} + +void _gfxw_set_ops_RECT(gfxw_widget_t *prim) { + _gfxw_set_ops(GFXW(prim), _gfxwop_rect_draw, _gfxwop_basic_free, _gfxwop_basic_tag, _gfxwop_rect_print, + _gfxwop_basic_compare_to, _gfxwop_primitive_equals, _gfxwop_basic_superarea_of); +} + +gfxw_primitive_t *gfxw_new_rect(rect_t rect, gfx_color_t color, gfx_line_mode_t line_mode, gfx_line_style_t line_style) { + gfxw_primitive_t *prim = _gfxw_new_primitive(rect, color, line_mode, line_style, GFXW_RECT); + prim->bounds.xl++; + prim->bounds.yl++; // Since it is actually one pixel bigger in each direction + + _gfxw_set_ops_RECT(GFXW(prim)); + + return prim; +} + +//*** Lines *** + +static int _gfxwop_line_draw(gfxw_widget_t *widget, Common::Point pos) { + gfxw_primitive_t *line = (gfxw_primitive_t *)widget; + rect_t linepos = widget->bounds; + Common::Point p1, p2; + + linepos.xl--; + linepos.yl--; + + if (widget->type == GFXW_INVERSE_LINE) { + linepos.x += linepos.xl; + linepos.xl = -linepos.xl; + } else { + DRAW_ASSERT(widget, GFXW_LINE); + } + + _split_rect(_move_rect(linepos, pos), &p1, &p2); + GFX_ASSERT(gfxop_draw_line(line->visual->gfx_state, p1, p2, line->color, line->line_mode, line->line_style)); + return 0; +} + +static int _gfxwop_line_print(gfxw_widget_t *widget, int indentation) { + _gfxw_print_widget(widget, indentation); + if (widget->type == GFXW_INVERSE_LINE) + sciprintf("INVERSE-LINE"); + else + sciprintf("LINE"); + + return 0; +} + +void _gfxw_set_ops_LINE(gfxw_widget_t *prim) { + _gfxw_set_ops(GFXW(prim), _gfxwop_line_draw, _gfxwop_basic_free, _gfxwop_basic_tag, _gfxwop_line_print, + _gfxwop_basic_compare_to, _gfxwop_primitive_equals, _gfxwop_basic_superarea_of); +} + +gfxw_primitive_t *gfxw_new_line(Common::Point start, Common::Point end, gfx_color_t color, gfx_line_mode_t line_mode, gfx_line_style_t line_style) { + gfxw_primitive_t *prim; + // Encode into internal representation + rect_t line = gfx_rect(start.x, start.y, end.x - start.x, end.y - start.y); + + byte inverse = 0; + + if (line.xl < 0) { + line.x += line.xl; + line.y += line.yl; + line.xl = -line.xl; + line.yl = -line.yl; + } + + if (line.yl < 0) { + inverse = 1; + line.x += line.xl; + line.xl = -line.xl; + } + + line.xl++; + line.yl++; + + prim = _gfxw_new_primitive(line, color, line_mode, line_style, inverse ? GFXW_INVERSE_LINE : GFXW_LINE); + + _gfxw_set_ops_LINE(GFXW(prim)); + + return prim; +} + +//*** Views and static views *** + +gfxw_view_t *_gfxw_new_simple_view(gfx_state_t *state, Common::Point pos, int view, int loop, int cel, int palette, int priority, int control, + gfx_alignment_t halign, gfx_alignment_t valign, int size, gfxw_widget_type_t type) { + gfxw_view_t *widget; + int width, height; + Common::Point offset; + + if (!state) { + GFXERROR("Attempt to create view widget with NULL state!\n"); + return NULL; + } + + if (gfxop_get_cel_parameters(state, view, loop, cel, &width, &height, &offset)) { + GFXERROR("Attempt to retrieve cel parameters for (%d/%d/%d) failed (Maybe the values weren't checked beforehand?)\n", + view, cel, loop); + return NULL; + } + + widget = (gfxw_view_t *)_gfxw_new_widget(size, type); + + widget->widget_priority = priority; + widget->pos = pos; + widget->color.mask = ((priority < 0) ? 0 : GFX_MASK_PRIORITY) | ((control < 0) ? 0 : GFX_MASK_CONTROL); + widget->color.priority = priority; + widget->color.control = control; + widget->view = view; + widget->loop = loop; + widget->cel = cel; + widget->palette = palette; + + if (halign == ALIGN_CENTER) + widget->pos.x -= width >> 1; + else if (halign == ALIGN_RIGHT) + widget->pos.x -= width; + + if (valign == ALIGN_CENTER) + widget->pos.y -= height >> 1; + else if (valign == ALIGN_BOTTOM) + widget->pos.y -= height; + + widget->bounds = gfx_rect(widget->pos.x - offset.x, widget->pos.y - offset.y, width, height); + + widget->flags |= GFXW_FLAG_VISIBLE; + + return widget; +} + +int _gfxwop_view_draw(gfxw_widget_t *widget, Common::Point pos) { + gfxw_view_t *view = (gfxw_view_t *)widget; + DRAW_ASSERT(widget, GFXW_VIEW); + + GFX_ASSERT(gfxop_draw_cel(view->visual->gfx_state, view->view, view->loop, view->cel, + Common::Point(view->pos.x + pos.x, view->pos.y + pos.y), view->color, view->palette)); + + return 0; +} + +static int _gfxwop_static_view_draw(gfxw_widget_t *widget, Common::Point pos) { + gfxw_view_t *view = (gfxw_view_t *)widget; + DRAW_ASSERT(widget, GFXW_VIEW); + + GFX_ASSERT(gfxop_draw_cel_static(view->visual->gfx_state, view->view, view->loop, + view->cel, _move_point(view->bounds, pos), view->color, view->palette)); + + return 0; +} + +static int _w_gfxwop_view_print(gfxw_widget_t *widget, const char *name, int indentation) { + gfxw_view_t *view = (gfxw_view_t *)widget; + _gfxw_print_widget(widget, indentation); + + sciprintf(name); + sciprintf("(%d/%d/%d)@(%d,%d)[p:%d,c:%d]", view->view, view->loop, view->cel, view->pos.x, view->pos.y, + (view->color.mask & GFX_MASK_PRIORITY) ? view->color.priority : -1, + (view->color.mask & GFX_MASK_CONTROL) ? view->color.control : -1); + + return 0; +} + +static int _gfxwop_view_print(gfxw_widget_t *widget, int indentation) { + return _w_gfxwop_view_print(widget, "VIEW", indentation); +} + +static int _gfxwop_static_view_print(gfxw_widget_t *widget, int indentation) { + return _w_gfxwop_view_print(widget, "PICVIEW", indentation); +} + +void _gfxw_set_ops_VIEW(gfxw_widget_t *view, char stat) { + _gfxw_set_ops(GFXW(view), (stat) ? _gfxwop_static_view_draw : _gfxwop_view_draw, _gfxwop_basic_free, + _gfxwop_basic_tag, (stat) ? _gfxwop_static_view_print : _gfxwop_view_print, + _gfxwop_basic_compare_to, _gfxwop_basic_equals, _gfxwop_basic_superarea_of); +} + +gfxw_view_t *gfxw_new_view(gfx_state_t *state, Common::Point pos, int view_nr, int loop, int cel, int palette, int priority, int control, + gfx_alignment_t halign, gfx_alignment_t valign, int flags) { + gfxw_view_t *view; + + if (flags & GFXW_VIEW_FLAG_DONT_MODIFY_OFFSET) { + int foo; + Common::Point offset; + gfxop_get_cel_parameters(state, view_nr, loop, cel, &foo, &foo, &offset); + pos.x += offset.x; + pos.y += offset.y; + } + + view = _gfxw_new_simple_view(state, pos, view_nr, loop, cel, palette, priority, control, halign, valign, + sizeof(gfxw_view_t), (flags & GFXW_VIEW_FLAG_STATIC) ? GFXW_STATIC_VIEW : GFXW_VIEW); + + _gfxw_set_ops_VIEW(GFXW(view), (char)(flags & GFXW_VIEW_FLAG_STATIC)); + + return view; +} + +//*** Dynamic Views *** + +static int _gfxwop_dyn_view_draw(gfxw_widget_t *widget, Common::Point pos) { + gfxw_dyn_view_t *view = (gfxw_dyn_view_t *) widget; + DRAW_ASSERT(widget, GFXW_DYN_VIEW); + + GFX_ASSERT(gfxop_draw_cel(view->visual->gfx_state, view->view, view->loop, + view->cel, _move_point(view->draw_bounds, pos), view->color, view->palette)); + + /* + gfx_color_t red; + red.visual.r = 0xff; + red.visual.g = red.visual.b = 0; + red.mask = GFX_MASK_VISUAL; + GFX_ASSERT(gfxop_draw_rectangle(view->visual->gfx_state, + gfx_rect(view->bounds.x + pos.x, view->bounds.y + pos.y, view->bounds.xl - 1, view->bounds.yl - 1), red, 0, 0)); + */ + + return 0; + +} + +static int _gfxwop_draw_nop(gfxw_widget_t *widget, Common::Point pos) { + return 0; +} + +static int _gfxwop_pic_view_draw(gfxw_widget_t *widget, Common::Point pos) { + gfxw_dyn_view_t *view = (gfxw_dyn_view_t *) widget; + DRAW_ASSERT(widget, GFXW_PIC_VIEW); + + GFX_ASSERT(gfxop_set_clip_zone(view->visual->gfx_state, view->parent->zone)); + GFX_ASSERT(gfxop_draw_cel_static_clipped(view->visual->gfx_state, view->view, view->loop, + view->cel, _move_point(view->draw_bounds, pos), view->color, view->palette)); + + // Draw again on the back buffer + GFX_ASSERT(gfxop_draw_cel(view->visual->gfx_state, view->view, view->loop, view->cel, + _move_point(view->draw_bounds, pos), view->color, view->palette)); + + + widget->draw = _gfxwop_draw_nop; // No more drawing needs to be done + + return 0; +} + +static int _gfxwop_some_view_print(gfxw_widget_t *widget, int indentation, const char *type_string) { + gfxw_dyn_view_t *view = (gfxw_dyn_view_t *)widget; + + _gfxw_print_widget(widget, indentation); + + sciprintf(type_string); + sciprintf(" SORT=%d z=%d seq=%d (%d/%d/%d)@(%d,%d)[p:%d,c:%d]; sig[%04x@%p]", view->force_precedence, view->z, + view->sequence, view->view, view->loop, view->cel, view->pos.x, view->pos.y, + (view->color.mask & GFX_MASK_PRIORITY) ? view->color.priority : -1, + (view->color.mask & GFX_MASK_CONTROL) ? view->color.control : -1, view->signal, view->signalp); + + return 0; +} + +static int _gfxwop_dyn_view_print(gfxw_widget_t *widget, int indentation) { + return _gfxwop_some_view_print(widget, indentation, "DYNVIEW"); +} + +static int _gfxwop_pic_view_print(gfxw_widget_t *widget, int indentation) { + return _gfxwop_some_view_print(widget, indentation, "PICVIEW"); +} + +static int _gfxwop_dyn_view_equals(gfxw_widget_t *widget, gfxw_widget_t *other) { + gfxw_dyn_view_t *wview = (gfxw_dyn_view_t *)widget, *oview; + if (!GFXW_IS_DYN_VIEW(other)) + return 0; + + oview = (gfxw_dyn_view_t *)other; + + if (wview->pos.x != oview->pos.x || wview->pos.y != oview->pos.y || wview->z != oview->z) + return 0; + + if (wview->view != oview->view || wview->loop != oview->loop || wview->cel != oview->cel) + return 0; + + if (!_color_equals(wview->color, oview->color)) + return 0; + + if (wview->flags != oview->flags) + return 0; + + return 1; +} + +static int _gfxwop_dyn_view_compare_to(gfxw_widget_t *widget, gfxw_widget_t *other) { + int retval; + gfxw_dyn_view_t *wview = (gfxw_dyn_view_t *) widget, *oview; + if (!GFXW_IS_DYN_VIEW(other)) + return 1; + + oview = (gfxw_dyn_view_t *) other; + + retval = wview->force_precedence - oview->force_precedence; + if (retval) + return retval; + + retval = wview->pos.y - oview->pos.y; + if (retval) + return retval; + + retval = (wview->z - oview->z); + if (retval) + return retval; + + return -(wview->sequence - oview->sequence); +} + +void _gfxw_set_ops_DYNVIEW(gfxw_widget_t *widget) { + _gfxw_set_ops(GFXW(widget), _gfxwop_dyn_view_draw, _gfxwop_basic_free, _gfxwop_basic_tag, + _gfxwop_dyn_view_print, _gfxwop_dyn_view_compare_to, _gfxwop_dyn_view_equals, _gfxwop_basic_superarea_of); +} + +void _gfxw_set_ops_PICVIEW(gfxw_widget_t *widget) { + _gfxw_set_ops_DYNVIEW(widget); + widget->draw = _gfxwop_pic_view_draw; + widget->print = _gfxwop_pic_view_print; +} + +gfxw_dyn_view_t *gfxw_new_dyn_view(gfx_state_t *state, Common::Point pos, int z, int view, int loop, int cel, int palette, int priority, int control, + gfx_alignment_t halign, gfx_alignment_t valign, int sequence) { + gfxw_dyn_view_t *widget; + int width, height; + int xalignmod, yalignmod; + Common::Point offset; + + if (!state) { + GFXERROR("Attempt to create view widget with NULL state!\n"); + return NULL; + } + + if (gfxop_get_cel_parameters(state, view, loop, cel, &width, &height, &offset)) { + GFXERROR("Attempt to retrieve cel parameters for (%d/%d/%d) failed (Maybe the values weren't checked beforehand?)\n", + view, cel, loop); + return NULL; + } + + widget = (gfxw_dyn_view_t *)_gfxw_new_widget(sizeof(gfxw_dyn_view_t), GFXW_DYN_VIEW); + + widget->pos = pos; + widget->color.mask = ((priority < 0) ? 0 : GFX_MASK_PRIORITY) | ((control < 0) ? 0 : GFX_MASK_CONTROL); + widget->widget_priority = priority; + widget->color.priority = priority; + widget->color.control = control; + widget->color.alpha = 0; + widget->color.visual.global_index = 0; + widget->color.visual.r = 0; + widget->color.visual.g = 0; + widget->color.visual.b = 0; + widget->view = view; + widget->loop = loop; + widget->cel = cel; + widget->sequence = sequence; + widget->force_precedence = 0; + widget->palette = palette; + + if (halign == ALIGN_CENTER) + xalignmod = width >> 1; + else if (halign == ALIGN_RIGHT) + xalignmod = width; + else + xalignmod = 0; + + if (valign == ALIGN_CENTER) + yalignmod = height >> 1; + else if (valign == ALIGN_BOTTOM) + yalignmod = height; + else + yalignmod = 0; + + widget->z = z; + + widget->draw_bounds = gfx_rect(widget->pos.x - xalignmod, widget->pos.y - yalignmod - z, width, height); + widget->bounds = gfx_rect(widget->pos.x - offset.x - xalignmod, widget->pos.y - offset.y - yalignmod - z, width, height); + + widget->flags |= GFXW_FLAG_VISIBLE; + + _gfxw_set_ops_DYNVIEW(GFXW(widget)); + + widget->signalp = NULL; + widget->signal = 0; + + return widget; +} + +//*** Text *** + +static int _gfxwop_text_free(gfxw_widget_t *widget) { + gfxw_text_t *text = (gfxw_text_t *)widget; + free(text->text); + + return _gfxwop_basic_free(widget); +} + +static int _gfxwop_text_draw(gfxw_widget_t *widget, Common::Point pos) { + gfxw_text_t *text = (gfxw_text_t *)widget; + DRAW_ASSERT(widget, GFXW_TEXT); + + GFX_ASSERT(gfxop_draw_text(text->visual->gfx_state, text->text_handle, _move_rect(text->bounds, pos))); + + return 0; +} + +static int _gfxwop_text_alloc_and_draw(gfxw_widget_t *widget, Common::Point pos) { + gfxw_text_t *text = (gfxw_text_t *)widget; + DRAW_ASSERT(widget, GFXW_TEXT); + + text->text_handle = gfxop_new_text(widget->visual->gfx_state, text->font_nr, text->text, text->bounds.xl, + text->halign, text->valign, text->color1, text->color2, text->bgcolor, text->text_flags); + + text->draw = _gfxwop_text_draw; + + return _gfxwop_text_draw(widget, pos); +} + +static int _gfxwop_text_print(gfxw_widget_t *widget, int indentation) { + _gfxw_print_widget(widget, indentation); + sciprintf("TEXT:'%s'", ((gfxw_text_t *)widget)->text); + + return 0; +} + +static int _gfxwop_text_equals(gfxw_widget_t *widget, gfxw_widget_t *other) { + gfxw_text_t *wtext = (gfxw_text_t *)widget, *otext; + if (other->type != GFXW_TEXT) + return 0; + + otext = (gfxw_text_t *)other; + + if ((wtext->bounds.x != otext->bounds.x) || (wtext->bounds.y != otext->bounds.y)) + return 0; + + if (wtext->halign != otext->halign || wtext->valign != otext->valign) + return 0; + + if (wtext->text_flags != otext->text_flags) + return 0; + + if (wtext->font_nr != otext->font_nr) + return 0; + + /* if (!(_color_equals(wtext->color1, otext->color1) && _color_equals(wtext->color2, otext->color2) + && _color_equals(wtext->bgcolor, otext->bgcolor))) + return 0; */ + + return 1; +} + +static int _gfxwop_text_should_replace(gfxw_widget_t *widget, gfxw_widget_t *other) { + gfxw_text_t *wtext = (gfxw_text_t *)widget, *otext; + + if (other->type != GFXW_TEXT) + return 0; + + otext = (gfxw_text_t *)other; + + return strcmp(wtext->text, otext->text); +} + +static int _gfxwop_text_compare_to(gfxw_widget_t *widget, gfxw_widget_t *other) { + return 1; +} + +void _gfxw_set_ops_TEXT(gfxw_widget_t *widget) { + _gfxw_set_ops(GFXW(widget), _gfxwop_text_alloc_and_draw, _gfxwop_text_free, _gfxwop_basic_tag, + _gfxwop_text_print, _gfxwop_text_compare_to, _gfxwop_text_equals, + _gfxwop_basic_superarea_of); + widget->should_replace = _gfxwop_text_should_replace; +} + +gfxw_text_t *gfxw_new_text(gfx_state_t *state, rect_t area, int font, const char *text, gfx_alignment_t halign, + gfx_alignment_t valign, gfx_color_t color1, gfx_color_t color2, gfx_color_t bgcolor, int text_flags) { + gfxw_text_t *widget = (gfxw_text_t *)_gfxw_new_widget(sizeof(gfxw_text_t), GFXW_TEXT); + + widget->widget_priority = _gfxw_color_get_priority(color1); + widget->font_nr = font; + widget->text = (char *)sci_malloc(strlen(text) + 1); + widget->halign = halign; + widget->valign = valign; + widget->color1 = color1; + widget->color2 = color2; + widget->bgcolor = bgcolor; + widget->text_flags = text_flags; + widget->text_handle = NULL; + + strcpy(widget->text, text); + + gfxop_get_text_params(state, font, text, area.xl, &(widget->width), &(widget->height), text_flags, + &(widget->lines_nr), &(widget->lineheight), &(widget->lastline_width)); + + /* FIXME: Window is too big + area.x += _calc_needmove(halign, area.xl, widget->width); + area.y += _calc_needmove(valign, area.yl, widget->height); + */ + + if (halign == ALIGN_LEFT) + area.xl = widget->width; + if (valign == ALIGN_TOP) + area.yl = widget->height; + + widget->bounds = area; + + widget->flags |= GFXW_FLAG_VISIBLE; + + _gfxw_set_ops_TEXT(GFXW(widget)); + + return widget; +} + +void gfxw_text_info(gfx_state_t *state, gfxw_text_t *text, int *lines, int *lineheight, int *offset) { + if (lines) + *lines = text->lines_nr; + if (lineheight) + *lineheight = text->lineheight; + if (offset) + *offset = text->lastline_width; +} + +//-- Container types -- + +static int _gfxwop_container_add_dirty_rel(gfxw_container_t *cont, rect_t rect, int propagate) { + DDIRTY(stderr, "->container_add_dirty_rel(%d,%d,%d,%d, %d)\n", GFX_PRINT_RECT(rect), propagate); + return cont->add_dirty_abs(cont, _move_rect(rect, Common::Point(cont->zone.x, cont->zone.y)), propagate); +} + +static inline void _gfxw_set_container_ops(gfxw_container_t *container, gfxw_point_op *draw, gfxw_op *free, gfxw_op *tag, + gfxw_op_int *print, gfxw_bin_op *compare_to, gfxw_bin_op *equals, + gfxw_bin_op *superarea_of, gfxw_visual_op *set_visual, + gfxw_unary_container_op *free_tagged, gfxw_unary_container_op *free_contents, + gfxw_rect_op *add_dirty, gfxw_container_op *add) { + _gfxw_set_ops(GFXW(container), draw, free, tag, print, compare_to, equals, superarea_of); + + container->free_tagged = free_tagged; + container->free_contents = free_contents; + container->add_dirty_abs = add_dirty; + container->add_dirty_rel = _gfxwop_container_add_dirty_rel; + container->add = add; + container->set_visual = set_visual; +} + +static int _w_gfxwop_container_print_contents(const char *name, gfxw_widget_t *widget, int indentation) { + gfxw_widget_t *seeker = widget; + + indent(indentation); + + sciprintf("--%s:\n", name); + + while (seeker) { + seeker->print(seeker, indentation + 1); + sciprintf("\n"); + seeker = seeker->next; + } + + return 0; +} + +static int _w_gfxwop_container_print(gfxw_widget_t *widget, int indentation) { + gfx_dirty_rect_t *dirty; + gfxw_container_t *container = (gfxw_container_t *)widget; + if (!GFXW_IS_CONTAINER(widget)) { + GFXERROR("_w_gfxwop_container_print() called on type %d widget\n", widget->type); + return 1; + } + + sciprintf(" viszone=((%d,%d),(%dx%d))\n", container->zone.x, container->zone.y, + container->zone.xl, container->zone.yl); + + indent(indentation); + sciprintf("--dirty:\n"); + + dirty = container->dirty; + while (dirty) { + indent(indentation + 1); + sciprintf("dirty(%d,%d, (%dx%d))\n", dirty->rect.x, dirty->rect.y, dirty->rect.xl, dirty->rect.yl); + dirty = dirty->next; + } + + _w_gfxwop_container_print_contents("contents", container->contents, indentation); + + return 0; +} + +gfxw_container_t *_gfxw_new_container_widget(rect_t area, int size, gfxw_widget_type_t type) { + gfxw_container_t *widget = (gfxw_container_t *)_gfxw_new_widget(size, type); + + widget->bounds = widget->zone = area; + widget->contents = NULL; + widget->nextpp = &(widget->contents); + widget->dirty = NULL; + + widget->flags |= GFXW_FLAG_VISIBLE | GFXW_FLAG_CONTAINER; + + return widget; +} + +static void recursively_free_dirty_rects(gfx_dirty_rect_t *dirty) { + if (dirty) { + recursively_free_dirty_rects(dirty->next); + free(dirty); + } +} + +int ti = 0; + +static inline int _gfxw_dirty_rect_overlaps_normal_rect(rect_t port_zone, rect_t bounds, rect_t dirty) { + bounds.x += port_zone.x; + bounds.y += port_zone.y; + + return gfx_rects_overlap(bounds, dirty); +} + +static int _gfxwop_container_draw_contents(gfxw_widget_t *widget, gfxw_widget_t *contents) { + gfxw_container_t *container = (gfxw_container_t *)widget; + gfx_dirty_rect_t *dirty = container->dirty; + gfx_state_t *gfx_state = (widget->visual) ? widget->visual->gfx_state : ((gfxw_visual_t *) widget)->gfx_state; + int draw_ports; + rect_t nullzone = {0, 0, 0, 0}; + + if (!contents) + return 0; + + while (dirty) { + gfxw_widget_t *seeker = contents; + + while (seeker) { + if (_gfxw_dirty_rect_overlaps_normal_rect(GFXW_IS_CONTAINER(seeker) ? nullzone : container->zone, + // Containers have absolute coordinates, reflect this. + seeker->bounds, dirty->rect)) { + + if (GFXW_IS_CONTAINER(seeker)) {// Propagate dirty rectangles /upwards/ + DDIRTY(stderr, "container_draw_contents: propagate upwards (%d,%d,%d,%d ,0)\n", GFX_PRINT_RECT(dirty->rect)); + ((gfxw_container_t *)seeker)->add_dirty_abs((gfxw_container_t *)seeker, dirty->rect, 0); + } + + seeker->flags |= GFXW_FLAG_DIRTY; + } + + seeker = seeker->next; + } + + dirty = dirty->next; + } + + // The draw loop is executed twice: Once for normal data, and once for ports. + for (draw_ports = 0; draw_ports < 2; draw_ports++) { + dirty = container->dirty; + + while (dirty) { + gfxw_widget_t *seeker = contents; + while (seeker && (draw_ports || !GFXW_IS_PORT(seeker))) { + rect_t small_rect; + byte draw_noncontainers; + + memcpy(&small_rect, &(dirty->rect), sizeof(rect_t)); + draw_noncontainers = !_gfxop_clip(&small_rect, container->bounds); + + if (seeker->flags & GFXW_FLAG_DIRTY) { + + if (!GFXW_IS_CONTAINER(seeker) && draw_noncontainers) { + GFX_ASSERT(gfxop_set_clip_zone(gfx_state, small_rect)); + } + /* Clip zone must be reset after each element, because we might + ** descend into containers. + ** Doing this is relatively cheap, though. */ + if (draw_noncontainers || GFXW_IS_CONTAINER(seeker)) + seeker->draw(seeker, Common::Point(container->zone.x, container->zone.y)); + + if (!dirty->next) + seeker->flags &= ~GFXW_FLAG_DIRTY; + } + + seeker = seeker->next; + } + dirty = dirty->next; + } + } + // Remember that the dirty rects should be freed afterwards! + + return 0; +} + +static int _gfxwop_container_free(gfxw_widget_t *widget) { + gfxw_container_t *container = (gfxw_container_t *)widget; + gfxw_widget_t *seeker = container->contents; + + while (seeker) { + gfxw_widget_t *next = seeker->next; + seeker->widfree(seeker); + seeker = next; + } + + recursively_free_dirty_rects(container->dirty); + container->dirty = NULL; + + return _gfxwop_basic_free(widget); +} + +static int _gfxwop_container_tag(gfxw_widget_t *widget) { + gfxw_container_t *container = (gfxw_container_t *) widget; + gfxw_widget_t *seeker = container->contents; + + while (seeker) { + seeker->tag(seeker); + seeker = seeker->next; + } + + return 0; +} + +static int _w_gfxwop_container_set_visual_contents(gfxw_widget_t *contents, gfxw_visual_t *visual) { + while (contents) { + contents->set_visual(contents, visual); + contents = contents->next; + } + return 0; +} + +static int _gfxwop_container_set_visual(gfxw_widget_t *widget, gfxw_visual_t *visual) { + gfxw_container_t *container = (gfxw_container_t *) widget; + + container->visual = visual; + if (widget->parent) { + if (!(GFXW_IS_LIST(widget) && !GFXWC(widget)->contents)) { + DDIRTY(stderr, "set_visual::DOWNWARDS abs(%d,%d,%d,%d, 1)\n", GFX_PRINT_RECT(widget->bounds)); + widget->parent->add_dirty_abs(widget->parent, widget->bounds, 1); + } + } + + return _w_gfxwop_container_set_visual_contents(container->contents, visual); +} + +static int _gfxwop_container_free_tagged(gfxw_container_t *container) { + gfxw_widget_t *seekerp = (container->contents); + + while (seekerp) { + gfxw_widget_t *redshirt = seekerp; + + if (redshirt->flags & GFXW_FLAG_TAGGED) { + seekerp = (redshirt->next); + redshirt->widfree(redshirt); + } else + seekerp = (seekerp)->next; + } + + return 0; +} + +static int _gfxwop_container_free_contents(gfxw_container_t *container) { + gfxw_widget_t *seeker = container->contents; + + while (seeker) { + gfxw_widget_t *next = seeker->next; + seeker->widfree(seeker); + seeker = next; + } + return 0; +} + +static void _gfxw_dirtify_container(gfxw_container_t *container, gfxw_widget_t *widget) { + if (GFXW_IS_CONTAINER(widget)) + container->add_dirty_abs(GFXWC(container), widget->bounds, 1); + else + container->add_dirty_rel(GFXWC(container), widget->bounds, 1); +} + +static int _parentize_widget(gfxw_container_t *container, gfxw_widget_t *widget) { + if (widget->parent) { + GFXERROR("_gfxwop_container_add(): Attempt to give second parent node to widget!\nWidget:"); + widget->print(GFXW(widget), 3); + sciprintf("\nContainer:"); + container->print(GFXW(container), 3); + + return 1; + } + + widget->parent = GFXWC(container); + + if (GFXW_IS_VISUAL(container)) + widget->set_visual(widget, (gfxw_visual_t *) container); + else if (container->visual) + widget->set_visual(widget, container->visual); + + return 0; +} + +static int _gfxw_container_id_equals(gfxw_container_t *container, gfxw_widget_t *widget) { + gfxw_widget_t **seekerp = &(container->contents); + + if (GFXW_IS_PORT(widget)) + return 0; + + if (widget->ID == GFXW_NO_ID) + return 0; + + while (*seekerp && ((*seekerp)->ID != widget->ID || (*seekerp)->subID != widget->subID)) + seekerp = &((*seekerp)->next); + + if (!*seekerp) + return 0; + + if ((*seekerp)->equals(*seekerp, widget) && !(*seekerp)->should_replace(*seekerp, widget)) { + widget->widfree(widget); + (*seekerp)->flags &= ~GFXW_FLAG_TAGGED; + return 1; + } else { + if (!(widget->flags & GFXW_FLAG_MULTI_ID)) + (*seekerp)->widfree(*seekerp); + return 0; + } +} + +static int _gfxwop_container_add_dirty(gfxw_container_t *container, rect_t dirty, int propagate) { +#if 0 + // This code has been disabled because containers may contain sub-containers with + // bounds greater than their own. + if (_gfxop_clip(&dirty, container->bounds)) + return 0; +#endif + + DDIRTY(stderr, "Effectively adding dirty %d,%d,%d,%d %d to ID %d\n", GFX_PRINT_RECT(dirty), propagate, container->ID); + container->dirty = gfxdr_add_dirty(container->dirty, dirty, GFXW_DIRTY_STRATEGY); + return 0; +} + +static int _gfxwop_container_add(gfxw_container_t *container, gfxw_widget_t *widget) { + if (_gfxw_container_id_equals(container, widget)) + return 0; + + if (_parentize_widget(container, widget)) + return 1; + + if (!(GFXW_IS_LIST(widget) && (!GFXWC(widget)->contents))) { // Don't dirtify self on empty lists + DDIRTY(stderr, "container_add: dirtify DOWNWARDS (%d,%d,%d,%d, 1)\n", GFX_PRINT_RECT(widget->bounds)); + _gfxw_dirtify_container(container, widget); + } + + *(container->nextpp) = widget; + container->nextpp = &(widget->next); + + return 0; +} + +//*** Lists and sorted lists *** + +static int _gfxwop_list_draw(gfxw_widget_t *list, Common::Point pos) { + DRAW_ASSERT(list, GFXW_LIST); + + _gfxwop_container_draw_contents(list, ((gfxw_list_t *)list)->contents); + recursively_free_dirty_rects(GFXWC(list)->dirty); + GFXWC(list)->dirty = NULL; + list->flags &= ~GFXW_FLAG_DIRTY; + + return 0; +} + +static int _gfxwop_sorted_list_draw(gfxw_widget_t *list, Common::Point pos) { + DRAW_ASSERT(list, GFXW_SORTED_LIST); + + _gfxwop_container_draw_contents(list, ((gfxw_list_t *)list)->contents); + recursively_free_dirty_rects(GFXWC(list)->dirty); + GFXWC(list)->dirty = NULL; + + return 0; +} + +static inline int _w_gfxwop_list_print(gfxw_widget_t *list, const char *name, int indentation) { + _gfxw_print_widget(list, indentation); + sciprintf(name); + + return _w_gfxwop_container_print(list, indentation); +} + +static int _gfxwop_list_print(gfxw_widget_t *list, int indentation) { + return _w_gfxwop_list_print(list, "LIST", indentation); +} + +static int _gfxwop_sorted_list_print(gfxw_widget_t *list, int indentation) { + return _w_gfxwop_list_print(list, "SORTED_LIST", indentation); +} + +#if 0 +struct gfxw_widget_list { + gfxw_widget_t *widget; + struct gfxw_widget_list *next; +}; + +static struct gfxw_widtet_list *_gfxw_make_widget_list_recursive(gfxw_widget_t *widget) { + gfxw_widget_list *node; + + if (!widget) + return NULL; + + node = sci_malloc(sizeof(struct gfxw_widget_list)); + node->widget = widget; + node->next = _gfxw_make_widget_list_recursive(widget->next); + + return node; +} + +static struct gfxw_widget_list *_gfxw_make_widget_list(gfxw_container_t *container) { + return _gfxw_make_widget_list_recursive(container->contents); +} +#endif + +static int _gfxwop_list_equals(gfxw_widget_t *widget, gfxw_widget_t *other) { + // Requires identical order of list elements. + gfxw_list_t *wlist, *olist; + + if (widget->type != other->type) + return 0; + + if (!GFXW_IS_LIST(widget)) { + GFXWARN("_gfxwop_list_equals(): Method called on non-list!\n"); + widget->print(widget, 0); + sciprintf("\n"); + return 0; + } + + wlist = (gfxw_list_t *)widget; + olist = (gfxw_list_t *)other; + + if (memcmp(&(wlist->bounds), &(olist->bounds), sizeof(rect_t))) + return 0; + + widget = wlist->contents; + other = olist->contents; + + while (widget && other) { + if (!(widget->equals(widget, other) && !widget->should_replace(widget, other))) + return 0; + + widget = widget->next; + other = other->next; + } + + return (!widget && !other); // True if both are finished now +} + +static int _gfxwop_list_add_dirty(gfxw_container_t *container, rect_t dirty, int propagate) { + // Lists add dirty boxes to both themselves and their parenting port/visual + + container->flags |= GFXW_FLAG_DIRTY; + + DDIRTY(stderr, "list_add_dirty %d,%d,%d,%d %d\n", GFX_PRINT_RECT(dirty), propagate); + if (propagate) + if (container->parent) { + DDIRTY(stderr, "->PROPAGATING\n"); + container->parent->add_dirty_abs(container->parent, dirty, 1); + } + + return _gfxwop_container_add_dirty(container, dirty, propagate); +} + +int _gfxwop_ordered_add(gfxw_container_t *container, gfxw_widget_t *widget, int compare_all) { + // O(n) + gfxw_widget_t **seekerp = &(container->contents); + + if (widget->next) { + GFXERROR("_gfxwop_sorted_list_add(): Attempt to add widget to two lists!\nWidget:"); + widget->print(GFXW(widget), 3); + sciprintf("\nList:"); + container->print(GFXW(container), 3); + BREAKPOINT(); + + return 1; + } + + if (_gfxw_container_id_equals(container, widget)) + return 0; + + while (*seekerp && (compare_all || (widget->compare_to(widget, *seekerp) >= 0))) { + + if (widget->equals(GFXW(widget), GFXW(*seekerp))) { + if (compare_all) { + if ((*seekerp)->visual) + (*seekerp)->widfree(GFXW(*seekerp)); // If it's a fresh widget + else + gfxw_annihilate(GFXW(*seekerp)); + + return _gfxwop_ordered_add(container, widget, compare_all); // We might have destroyed the container's contents + } else { + widget->next = (*seekerp)->next; + (*seekerp)->widfree(GFXW(*seekerp)); + *seekerp = widget; + return (_parentize_widget(container, widget)); + } + } + + if (*seekerp) + seekerp = &((*seekerp)->next); + } + + widget->next = *seekerp; + *seekerp = widget; + + return _parentize_widget(container, widget); +} + +static int _gfxwop_sorted_list_add(gfxw_container_t *container, gfxw_widget_t *widget) { + // O(n) + return _gfxwop_ordered_add(container, widget, 0); +} + +void _gfxw_set_ops_LIST(gfxw_container_t *list, char sorted) { + _gfxw_set_container_ops((gfxw_container_t *)list, sorted ? _gfxwop_sorted_list_draw : _gfxwop_list_draw, + _gfxwop_container_free, _gfxwop_container_tag, + sorted ? _gfxwop_sorted_list_print : _gfxwop_list_print, + _gfxwop_basic_compare_to, sorted ? _gfxwop_basic_equals : _gfxwop_list_equals, + _gfxwop_basic_superarea_of, _gfxwop_container_set_visual, + _gfxwop_container_free_tagged, _gfxwop_container_free_contents, + _gfxwop_list_add_dirty, sorted ? _gfxwop_sorted_list_add : _gfxwop_container_add); +} + +gfxw_list_t *gfxw_new_list(rect_t area, int sorted) { + gfxw_list_t *list = (gfxw_list_t *) _gfxw_new_container_widget(area, sizeof(gfxw_list_t), + sorted ? GFXW_SORTED_LIST : GFXW_LIST); + + _gfxw_set_ops_LIST(GFXWC(list), (char)sorted); + + return list; +} + +//*** Visuals *** + +static int _gfxwop_visual_draw(gfxw_widget_t *widget, Common::Point pos) { + gfxw_visual_t *visual = (gfxw_visual_t *) widget; + gfx_dirty_rect_t *dirty = visual->dirty; + DRAW_ASSERT(widget, GFXW_VISUAL); + + while (dirty) { + int err = gfxop_clear_box(visual->gfx_state, dirty->rect); + + if (err) { + GFXERROR("Error while clearing dirty rect (%d,%d,(%dx%d))\n", dirty->rect.x, + dirty->rect.y, dirty->rect.xl, dirty->rect.yl); + if (err == GFX_FATAL) + return err; + } + + dirty = dirty->next; + } + + _gfxwop_container_draw_contents(widget, visual->contents); + + recursively_free_dirty_rects(visual->dirty); + visual->dirty = NULL; + widget->flags &= ~GFXW_FLAG_DIRTY; + + return 0; +} + +static int _gfxwop_visual_free(gfxw_widget_t *widget) { + gfxw_visual_t *visual = (gfxw_visual_t *) widget; + gfxw_port_t **portrefs; + int retval; + + if (!GFXW_IS_VISUAL(visual)) { + GFXERROR("_gfxwop_visual_free() called on non-visual!Widget was: "); + widget->print(widget, 3); + return 1; + } + + portrefs = visual->port_refs; + + retval = _gfxwop_container_free(widget); + + free(portrefs); + + return 0; +} + +static int _gfxwop_visual_print(gfxw_widget_t *widget, int indentation) { + int i; + int comma = 0; + gfxw_visual_t *visual = (gfxw_visual_t *) widget; + + if (!GFXW_IS_VISUAL(visual)) { + GFXERROR("_gfxwop_visual_free() called on non-visual!Widget was: "); + widget->print(widget, 3); + return 1; + } + + _gfxw_print_widget(widget, indentation); + sciprintf("VISUAL; ports={"); + for (i = 0; i < visual->port_refs_nr; i++) + if (visual->port_refs[i]) { + if (comma) + sciprintf(","); + else + comma = 1; + + sciprintf("%d", i); + } + sciprintf("}\n"); + + return _w_gfxwop_container_print(widget, indentation); +} + +static int _gfxwop_visual_set_visual(gfxw_widget_t *self, gfxw_visual_t *visual) { + if (self != GFXW(visual)) { + GFXWARN("Attempt to set a visual's parent visual to something else!\n"); + } else { + GFXWARN("Attempt to set a visual's parent visual!\n"); + } + + return 1; +} + +void _gfxw_set_ops_VISUAL(gfxw_container_t *visual) { + _gfxw_set_container_ops((gfxw_container_t *)visual, _gfxwop_visual_draw, _gfxwop_visual_free, + _gfxwop_container_tag, _gfxwop_visual_print, _gfxwop_basic_compare_to, + _gfxwop_basic_equals, _gfxwop_basic_superarea_of, _gfxwop_visual_set_visual, + _gfxwop_container_free_tagged, _gfxwop_container_free_contents, + _gfxwop_container_add_dirty, _gfxwop_container_add); +} + +gfxw_visual_t *gfxw_new_visual(gfx_state_t *state, int font) { + gfxw_visual_t *visual = (gfxw_visual_t *) _gfxw_new_container_widget(gfx_rect(0, 0, 320, 200), sizeof(gfxw_visual_t), GFXW_VISUAL); + + visual->font_nr = font; + visual->gfx_state = state; + + visual->port_refs_nr = 16; + visual->port_refs = (gfxw_port_t **)sci_calloc(sizeof(gfxw_port_t), visual->port_refs_nr); + + _gfxw_set_ops_VISUAL(GFXWC(visual)); + + return visual; +} + +static int _visual_find_free_ID(gfxw_visual_t *visual) { + int id = 0; + int newports = 16; + + while (visual->port_refs[id] && id < visual->port_refs_nr) + id++; + + if (id == visual->port_refs_nr) { // Out of ports? + visual->port_refs_nr += newports; + visual->port_refs = (gfxw_port_t**)sci_realloc(visual->port_refs, visual->port_refs_nr); + memset(visual->port_refs + id, 0, newports * sizeof(gfxw_port_t *)); // Clear new port refs + } + + return id; +} + +static int _gfxwop_add_dirty_rects(gfxw_container_t *dest, gfx_dirty_rect_t *src) { + DDIRTY(stderr, "Adding multiple dirty to #%d\n", dest->ID); + if (src) { + dest->dirty = gfxdr_add_dirty(dest->dirty, src->rect, GFXW_DIRTY_STRATEGY); + _gfxwop_add_dirty_rects(dest, src->next); + } + + return 0; +} + +//*** Ports *** + +static int _gfxwop_port_draw(gfxw_widget_t *widget, Common::Point pos) { + gfxw_port_t *port = (gfxw_port_t *) widget; + DRAW_ASSERT(widget, GFXW_PORT); + + if (port->decorations) { + DDIRTY(stderr, "Getting/applying deco dirty (multi)\n"); + _gfxwop_add_dirty_rects(GFXWC(port->decorations), port->dirty); + if (port->decorations->draw(GFXW(port->decorations), gfxw_point_zero)) { + port->decorations->dirty = NULL; + return 1; + } + port->decorations->dirty = NULL; + } + + _gfxwop_container_draw_contents(widget, port->contents); + + recursively_free_dirty_rects(port->dirty); + port->dirty = NULL; + widget->flags &= ~GFXW_FLAG_DIRTY; + + return 0; +} + +static int _gfxwop_port_free(gfxw_widget_t *widget) { + gfxw_port_t *port = (gfxw_port_t *) widget; + + if (port->visual) { + gfxw_visual_t *visual = port->visual; + int ID = port->ID; + + if (ID < 0 || ID >= visual->port_refs_nr) { + GFXWARN("Attempt to free port #%d; allowed: [0..%d]!\n", ID, visual->port_refs_nr); + return GFX_ERROR; + } + + if (visual->port_refs[ID] != port) { + GFXWARN("While freeing port %d: Port is at %p, but port list indicates %p", ID, (void *)port, (void *)visual->port_refs[ID]); + } else + visual->port_refs[ID] = NULL; + + } + + if (port->decorations) + port->decorations->widfree(GFXW(port->decorations)); + + return _gfxwop_container_free(widget); +} + +static int _gfxwop_port_print(gfxw_widget_t *widget, int indentation) { + gfxw_port_t *port = (gfxw_port_t *)widget; + + _gfxw_print_widget(widget, indentation); + sciprintf("PORT"); + sciprintf(" font=%d drawpos=(%d,%d)", port->font_nr, port->draw_pos.x, port->draw_pos.y); + if (port->gray_text) + sciprintf(" (gray)"); + _w_gfxwop_container_print(GFXW(port), indentation); + + return _w_gfxwop_container_print_contents("decorations", GFXW(port->decorations), indentation); +} + +static int _gfxwop_port_superarea_of(gfxw_widget_t *self, gfxw_widget_t *other) { + gfxw_port_t *port = (gfxw_port_t *) self; + + if (!port->port_bg) + return _gfxwop_basic_superarea_of(self, other); + + return port->port_bg->superarea_of(port->port_bg, other); +} + +static int _gfxwop_port_set_visual(gfxw_widget_t *widget, gfxw_visual_t *visual) { + gfxw_list_t *decorations = ((gfxw_port_t *) widget)->decorations; + widget->visual = visual; + + if (decorations) + if (decorations->set_visual(GFXW(decorations), visual)) { + GFXWARN("Setting the visual for decorations failed for port "); + widget->print(widget, 1); + return 1; + } + + return _gfxwop_container_set_visual(widget, visual); +} + +static int _gfxwop_port_add_dirty(gfxw_container_t *widget, rect_t dirty, int propagate) { + gfxw_port_t *self = (gfxw_port_t *) widget; + + self->flags |= GFXW_FLAG_DIRTY; + + _gfxwop_container_add_dirty(widget, dirty, propagate); + + DDIRTY(stderr, "Added dirty to ID %d\n", widget->ID); + DDIRTY(stderr, "dirty= (%d,%d,%d,%d) bounds (%d,%d,%d,%d)\n", dirty.x, dirty.x, dirty.xl, dirty.yl, + widget->bounds.x, widget->bounds.y, widget->bounds.xl, widget->bounds.yl); +#if 0 + // FIXME: This is a worthwhile optimization + if (self->port_bg) { + gfxw_widget_t foo; + + foo.bounds = dirty; // Yeah, sub-elegant, I know + foo.bounds.x -= self->zone.x; + foo.bounds.y -= self->zone.y; + if (self->port_bg->superarea_of(self->port_bg, &foo)) { + gfxw_container_t *parent = self->parent; + while (parent) { + fprintf(stderr, "Dirtifying parent id %d\n", parent->ID); + parent->flags |= GFXW_FLAG_DIRTY; + parent = parent->parent; + } + return 0; + } + } // else propagate to the parent, since we're not 'catching' the dirty rect +#endif + + if (propagate) + if (self->parent) { + DDIRTY(stderr, "PROPAGATE\n"); + return self->parent->add_dirty_abs(self->parent, dirty, 1); + } + + return 0; +} + +static int _gfxwop_port_add(gfxw_container_t *container, gfxw_widget_t *widget) { + // O(n) + return _gfxwop_ordered_add(container, widget, 1); +} + +void _gfxw_set_ops_PORT(gfxw_container_t *widget) { + _gfxw_set_container_ops((gfxw_container_t *)widget, _gfxwop_port_draw, _gfxwop_port_free, _gfxwop_container_tag, + _gfxwop_port_print, _gfxwop_basic_compare_to, _gfxwop_basic_equals, _gfxwop_port_superarea_of, + _gfxwop_port_set_visual, _gfxwop_container_free_tagged, _gfxwop_container_free_contents, + _gfxwop_port_add_dirty, _gfxwop_port_add); +} + +gfxw_port_t *gfxw_new_port(gfxw_visual_t *visual, gfxw_port_t *predecessor, rect_t area, gfx_color_t fgcolor, gfx_color_t bgcolor) { + gfxw_port_t *widget = (gfxw_port_t *)_gfxw_new_container_widget(area, sizeof(gfxw_port_t), GFXW_PORT); + + VERIFY_WIDGET(visual); + + widget->port_bg = NULL; + widget->parent = NULL; + widget->decorations = NULL; + widget->title_text = NULL; + widget->draw_pos = Common::Point(0, 0); + widget->gray_text = 0; + widget->color = fgcolor; + widget->bgcolor = bgcolor; + widget->font_nr = visual->font_nr; + widget->ID = _visual_find_free_ID(visual); + widget->chrono_port = 0; + visual->port_refs[widget->ID] = widget; + + _gfxw_set_ops_PORT(GFXWC(widget)); + + return widget; +} + +void gfxw_port_auto_restore_background(gfxw_visual_t *visual, gfxw_port_t *window, rect_t auto_rect) { + window->port_flags |= WINDOW_FLAG_AUTO_RESTORE; + window->restore_snap = gfxw_make_snapshot(visual, auto_rect); +} + +gfxw_port_t *gfxw_remove_port(gfxw_visual_t *visual, gfxw_port_t *port) { + gfxw_port_t *parent; + VERIFY_WIDGET(visual); + VERIFY_WIDGET(port); + + if (!visual->contents) { + GFXWARN("Attempt to remove port from empty visual\n"); + return NULL; + } + + parent = (gfxw_port_t *)port->parent; + if (port->port_flags & WINDOW_FLAG_AUTO_RESTORE) + gfxw_restore_snapshot(visual, port->restore_snap); + + if (port->widfree(GFXW(port))) + return parent; + + while (parent && !GFXW_IS_PORT(parent)) + parent = (gfxw_port_t *)parent->parent; // Ascend through ancestors + + return parent; +} + +gfxw_port_t *gfxw_find_port(gfxw_visual_t *visual, int ID) { + if (ID < 0 || ID >= visual->port_refs_nr) + return NULL; + + return visual->port_refs[ID]; +} + +gfxw_port_t *gfxw_find_default_port(gfxw_visual_t *visual) { + int id = visual->port_refs_nr; + + while (id--) { + gfxw_port_t *port = visual->port_refs[id]; + + if (port) + return port; + } + + return NULL; +} + +// - other functions - + +gfxw_widget_t *gfxw_set_id(gfxw_widget_t *widget, int ID, int subID) { + if (widget) { + widget->ID = ID; + widget->subID = subID; + } + + return widget; +} + +gfxw_dyn_view_t *gfxw_dyn_view_set_params(gfxw_dyn_view_t *widget, int under_bits, void *under_bitsp, int signal, void *signalp) { + if (!widget) + return NULL; + + widget->under_bits = under_bits; + widget->under_bitsp = under_bitsp; + widget->signal = signal; + widget->signalp = signalp; + + return widget; +} + +gfxw_widget_t *gfxw_remove_id(gfxw_container_t *container, int ID, int subID) { + gfxw_widget_t **wp = &(container->contents); + + while (*wp) { + if ((*wp)->ID == ID && (subID == GFXW_NO_ID || (*wp)->subID == subID)) { + gfxw_widget_t *widget = *wp; + + *wp = (*wp)->next; + widget->next = NULL; + widget->parent = NULL; + widget->visual = NULL; + + return widget; + } + + wp = &((*wp)->next); + } + + return NULL; +} + +gfxw_widget_t *gfxw_hide_widget(gfxw_widget_t *widget) { + if (widget->flags & GFXW_FLAG_VISIBLE) { + widget->flags &= ~GFXW_FLAG_VISIBLE; + + if (widget->parent) + widget->parent->add_dirty_rel(widget->parent, widget->bounds, 1); + } + + return widget; +} + +gfxw_widget_t *gfxw_show_widget(gfxw_widget_t *widget) { + if (!(widget->flags & GFXW_FLAG_VISIBLE)) { + widget->flags |= GFXW_FLAG_VISIBLE; + + if (widget->parent) + widget->parent->add_dirty_rel(widget->parent, widget->bounds, 1); + } + + return widget; +} + +gfxw_snapshot_t *gfxw_make_snapshot(gfxw_visual_t *visual, rect_t area) { + gfxw_snapshot_t *retval = (gfxw_snapshot_t*)sci_malloc(sizeof(gfxw_snapshot_t)); + + retval->serial = widget_serial_number_counter++; + + retval->area = area; + + // Work around subset semantics in gfx_rect_subset. + // This fixes the help icon in LSL5. */ + if (retval->area.xl == 320) retval->area.xl = 321; + + return retval; +} + +int gfxw_widget_matches_snapshot(gfxw_snapshot_t *snapshot, gfxw_widget_t *widget) { + int free_below = (snapshot->serial < widget_serial_number_counter) ? 0 : widget_serial_number_counter; + int free_above_eq = snapshot->serial; + rect_t bounds = widget->bounds; + + if (!GFXW_IS_CONTAINER(widget) && widget->parent) { + bounds.x += widget->parent->bounds.x; + bounds.y += widget->parent->bounds.y; + } + + return ((widget->serial >= free_above_eq || widget->serial < free_below) && gfx_rect_subset(bounds, snapshot->area)); +} + +#define MAGIC_FREE_NUMBER -42 + +void _gfxw_free_contents_appropriately(gfxw_container_t *container, gfxw_snapshot_t *snapshot, int priority) { + gfxw_widget_t *widget = container->contents; + + while (widget) { + gfxw_widget_t *next = widget->next; + + if (gfxw_widget_matches_snapshot(snapshot, widget) && !(widget->flags & GFXW_FLAG_IMMUNE_TO_SNAPSHOTS) + && (priority == MAGIC_FREE_NUMBER || priority <= widget->widget_priority || widget->widget_priority == -1)) { + widget->widfree(widget); + } else { + if (GFXW_IS_CONTAINER(widget)) + _gfxw_free_contents_appropriately(GFXWC(widget), snapshot, priority); + } + + widget = next; + } +} + +gfxw_snapshot_t *gfxw_restore_snapshot(gfxw_visual_t *visual, gfxw_snapshot_t *snapshot) { + _gfxw_free_contents_appropriately(GFXWC(visual), snapshot, MAGIC_FREE_NUMBER); + + return snapshot; +} + +void gfxw_annihilate(gfxw_widget_t *widget) { + gfxw_visual_t *visual = widget->visual; + int widget_priority = 0; + int free_overdrawn = 0; + + gfxw_snapshot_t snapshot; + if (!GFXW_IS_CONTAINER(widget) && widget->parent && visual && (widget->flags & GFXW_FLAG_VISIBLE)) { + snapshot.serial = 0; + snapshot.area = widget->bounds; + snapshot.area.x += widget->parent->zone.x; + snapshot.area.y += widget->parent->zone.y; + free_overdrawn = 1; + widget_priority = widget->widget_priority; + } + + widget->widfree(GFXW(widget)); + + if (free_overdrawn) + _gfxw_free_contents_appropriately(GFXWC(visual), &snapshot, widget_priority); +} + +gfxw_dyn_view_t *gfxw_picviewize_dynview(gfxw_dyn_view_t *dynview) { + dynview->type = GFXW_PIC_VIEW; + dynview->flags |= GFXW_FLAG_DIRTY; + + _gfxw_set_ops_PICVIEW(GFXW(dynview)); + + if (dynview->parent) + _gfxw_dirtify_container(dynview->parent, GFXW(dynview)); + + return dynview; +} + +// Chrono-Ports (tm) + +gfxw_port_t * gfxw_get_chrono_port(gfxw_visual_t *visual, gfxw_list_t **temp_widgets_list, int flags) { + gfxw_port_t *result = NULL; + gfx_color_t transparent = {{0, 0, 0, 0}, 0, 0, 0, 0}; + int id = 0; + + if (!(flags & GFXW_CHRONO_NON_TOPMOST)) { + result = gfxw_find_default_port(visual); + } else { + id = visual->port_refs_nr; + while (id >= 0 && (!visual->port_refs[id] || !visual->port_refs[id]->chrono_port)) + id--; + + if (id >= 0) + result = visual->port_refs[id]; + } + + if (!result || !result->chrono_port) { + if (flags & GFXW_CHRONO_NO_CREATE) + return NULL; + result = gfxw_new_port(visual, NULL, gfx_rect(0, 0, 320, 200), transparent, transparent); + *temp_widgets_list = gfxw_new_list(gfx_rect(0, 0, 320, 200), 1); + result->add(GFXWC(result), GFXW(*temp_widgets_list)); + result->chrono_port = 1; + if (temp_widgets_list) + *temp_widgets_list = GFXWC(result->contents); + return result; + }; + + if (temp_widgets_list) + *temp_widgets_list = GFXWC(result->contents); + + return result; +} + +static int gfxw_check_chrono_overlaps(gfxw_port_t *chrono, gfxw_widget_t *widget) { + gfxw_widget_t *seeker = GFXWC(chrono->contents)->contents; + + while (seeker) { + if (gfx_rect_equals(seeker->bounds, widget->bounds)) { + gfxw_annihilate(GFXW(seeker)); + return 1; + } + + seeker = seeker->next; + } + + return 0; +} + +void gfxw_add_to_chrono(gfxw_visual_t *visual, gfxw_widget_t *widget) { + gfxw_list_t *tw; + gfxw_port_t *chrono = gfxw_get_chrono_port(visual, &tw, 0); + + gfxw_check_chrono_overlaps(chrono, widget); + chrono->add(GFXWC(chrono), widget); +} + +static gfxw_widget_t *gfxw_widget_intersects_chrono(gfxw_list_t *tw, gfxw_widget_t *widget) { + gfxw_widget_t *seeker; + + assert(tw->type == GFXW_SORTED_LIST); + + seeker = tw->contents; + while (seeker) { + Common::Point origin; + rect_t bounds = widget->bounds; + + bounds = widget->bounds; + origin.x = seeker->parent->zone.x; + origin.y = seeker->parent->zone.y; + gfx_rect_translate(bounds, origin); + + if (gfx_rects_overlap(bounds, seeker->bounds)) + return seeker; + + seeker = seeker->next; + } + + return 0; +} + +void gfxw_widget_reparent_chrono(gfxw_visual_t *visual, gfxw_widget_t *view, gfxw_list_t *target) { + gfxw_list_t *tw; + gfxw_port_t *chrono; + gfxw_widget_t *intersector; + + chrono = gfxw_get_chrono_port(visual, &tw, GFXW_CHRONO_NO_CREATE); + if (chrono == NULL) + return; + + intersector = gfxw_widget_intersects_chrono(tw, view); + if (intersector) { + Common::Point origin = Common::Point(intersector->parent->zone.x, intersector->parent->zone.y); + + gfxw_remove_widget_from_container(GFXWC(chrono), GFXW(tw)); + gfxw_remove_widget_from_container(GFXWC(chrono->parent), GFXW(chrono)); + gfxw_annihilate(GFXW(chrono)); + + gfx_rect_translate(tw->zone, origin); + target->add(GFXWC(target), GFXW(tw)); + } +} + +void gfxw_widget_kill_chrono(gfxw_visual_t *visual, int window) { + int i; + + for (i = window; i < visual->port_refs_nr ; i++) { + if (visual->port_refs[i] && visual->port_refs[i]->chrono_port) + gfxw_annihilate(GFXW(visual->port_refs[i])); + } +} + +} // End of namespace Sci diff --git a/engines/sci/gfx/menubar.h b/engines/sci/gfx/menubar.h index c262cd5bbf..5255ccb96a 100644 --- a/engines/sci/gfx/menubar.h +++ b/engines/sci/gfx/menubar.h @@ -29,7 +29,7 @@ #define SCI_GFX_SCI_MENUBAR_H #include "sci/include/vm_types.h" -#include "sci/gfx/gfx_operations.h" +#include "sci/gfx/operations.h" #include "sci/gfx/gfx_widgets.h" namespace Sci { diff --git a/engines/sci/gfx/operations.cpp b/engines/sci/gfx/operations.cpp index 26b0207695..bcdc12223e 100644 --- a/engines/sci/gfx/operations.cpp +++ b/engines/sci/gfx/operations.cpp @@ -26,7 +26,7 @@ // Graphical operations, called from the widget state manager #include "sci/sci_memory.h" -#include "sci/gfx/gfx_operations.h" +#include "sci/gfx/operations.h" #include "common/system.h" diff --git a/engines/sci/gfx/operations.h b/engines/sci/gfx/operations.h new file mode 100644 index 0000000000..d3cdedceac --- /dev/null +++ b/engines/sci/gfx/operations.h @@ -0,0 +1,682 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* Graphical operations, called from the widget state manager */ + +#ifndef SCI_GFX_GFX_OPERATIONS_H +#define SCI_GFX_GFX_OPERATIONS_H + +#include "sci/gfx/gfx_resmgr.h" +#include "sci/gfx/gfx_tools.h" +#include "sci/gfx/gfx_options.h" +#include "sci/gfx/gfx_system.h" +#include "sci/include/uinput.h" + +namespace Sci { + +#define GFXOP_NO_POINTER -1 + +/* Threshold in color index mode to differentiate between visible and non-visible stuff. +** GFXOP_ALPHA_THRESHOLD itself should be treated as non-visible. +*/ +#define GFXOP_ALPHA_THRESHOLD 0xff + +struct gfx_text_handle_t { + char *text; /* Copy of the actual text */ + + int lines_nr; + int line_height; + text_fragment_t *lines; /* Text offsets */ + gfx_bitmap_font_t *font; + gfx_pixmap_t **text_pixmaps; + + int width, height; + + int priority, control; + gfx_alignment_t halign, valign; +}; + +/* Unless individually stated otherwise, the following applies: +** All operations herein apply to the standard 320x200 coordinate system. +** All operations perform clipping relative to state->clip_zone. +*/ + +typedef enum { + GFX_BOX_SHADE_FLAT, + GFX_BOX_SHADE_RIGHT, + GFX_BOX_SHADE_LEFT, + GFX_BOX_SHADE_DOWN, + GFX_BOX_SHADE_UP +#if 0 + /* possible with alphaing, but there is no way to check for + ** alpha capability of gfx_driver->draw_filled_rect() yet + */ + , GFX_BOX_SHADE_RIGHT_DOWN, + GFX_BOX_SHADE_LEFT_DOWN, + GFX_BOX_SHADE_RIGHT_UP, + GFX_BOX_SHADE_LEFT_UP +#endif +} gfx_box_shade_t; + + +struct gfx_dirty_rect_t { + rect_t rect; + gfx_dirty_rect_t *next; +}; + + +struct gfx_input_event_t { + sci_event_t event; + gfx_input_event_t *next; +}; + +struct gfx_state_t { + int version; /* Interpreter version */ + + gfx_options_t *options; + + Common::Point pointer_pos; /* Mouse pointer coordinates */ + + rect_t clip_zone_unscaled; /* The current UNSCALED clipping zone */ + rect_t clip_zone; /* The current SCALED clipping zone; a cached scaled version of clip_zone_unscaled */ + + gfx_driver_t *driver; + gfx_pixmap_color_t *static_palette; /* Null for dynamic palettes */ + int static_palette_entries; + + int visible_map; + + gfx_resstate_t *resstate; /* Resource state */ + + gfx_pixmap_t *priority_map; /* back buffer priority map (unscaled) */ + gfx_pixmap_t *static_priority_map; /* static buffer priority map (unscaled) */ + gfx_pixmap_t *control_map; /* back buffer control map (only exists unscaled in the first place) */ + + + int mouse_pointer_visible; /* Whether the pointer is drawn right now */ + Common::Point old_pointer_draw_pos; /* Mouse pointer draw coordinates */ + rect_t pointer_bg_zone; /* old-pointer-draw-pos relative zone inside the pointer + ** pixmap that was drawn */ + + int mouse_pointer_in_hw; /* Current pointer is being handled in hardware */ + + gfx_pixmap_t *mouse_pointer; /* Only set when drawing the mouse manually */ + gfx_pixmap_t *mouse_pointer_bg; /* Background under the pointer */ + + int tag_mode; /* Set to 1 after a new pic is drawn and the resource manager + ** has tagged all resources. Reset after the next front buffer + ** update is done, when all resources that are still tagged are + ** flushed. */ + + int disable_dirty; /* Set to 1 to disable dirty rect accounting */ + + int pic_nr; /* Number of the current pic */ + int palette_nr; /* Palette number of the current pic */ + + gfx_input_event_t *events; + + gfx_pixmap_t *fullscreen_override; /* An optional override picture which must have unscaled + ** full-screen size, which overrides all other visibility, and + ** which is generally slow */ + + gfxr_pic_t *pic, *pic_unscaled; /* The background picture and its unscaled equivalent */ + + gfx_dirty_rect_t *dirty_rects; /* Dirty rectangles */ + + void *internal_state; /* Internal interpreter information */ + +}; + + +/**************************/ +/* Fundamental operations */ +/**************************/ + +int gfxop_init_default(gfx_state_t *state, gfx_options_t *options, void *misc_info); +/* Initializes a graphics mode suggested by the graphics driver +** Parameters: (gfx_state_ t *) state: The state to initialize in that mode +** (gfx_options_t *) options: Rendering options +** (void *) misc_info: Additional information for the interpreter +** part of the resource loader +** Returns : (int) GFX_OK on success, GFX_FATAL otherwise +*/ + +int gfxop_init(gfx_state_t *state, int xfact, int yfact, gfx_color_mode_t bpp, + gfx_options_t *options, void *misc_info); +/* Initializes a custom graphics mode +** Parameters: (gfx_state_t *) state: The state to initialize +** (int x int) xfact, yfact: Horizontal and vertical scale factors +** (gfx_color_mode_t) bpp: Bytes per pixel to initialize with, or +** 0 (GFX_COLOR_MODE_AUTO) to auto-detect +** (gfx_options_t *) options: Rendering options +** (void *) misc_info: Additional information for the interpreter +** part of the resource loader +** Returns : (int) GFX_OK on success, GFX_ERROR if that particular mode is +** unavailable, or GFX_FATAL if the graphics driver is unable +** to provide any useful graphics support +*/ + +int gfxop_set_parameter(gfx_state_t *state, char *attribute, char *value); +/* Sets a driver-specific parameter +** Parameters: (gfx_state_t *) state: The state, encapsulating the driver object to manipulate +** (char *) attribute: The attribute to set +** (char *) value: The value the attribute should be set to +** Returns : (int) GFX_OK on success, GFX_FATAL on fatal error conditions triggered +** by the command +*/ + +int gfxop_exit(gfx_state_t *state); +/* Deinitializes a currently active driver +** Parameters: (gfx_state_t *) state: The state encapsulating the driver in question +** Returns : (int) GFX_OK +*/ + +int gfxop_scan_bitmask(gfx_state_t *state, rect_t area, gfx_map_mask_t map); +/* Calculates a bit mask calculated from some pixels on the specified map +** Parameters: (gfx_state_t *) state: The state containing the pixels to scan +** (rect_t) area: The area to check +** (gfx_map_mask_t) map: The GFX_MASKed map(s) to test +** Returns : (int) An integer value where, for each 0<=i<=15, bit #i is set +** iff there exists a map for which the corresponding bit was set +** in the 'map' parameter and for which there exists a pixel within +** the specified area so that the pixel's lower 4 bits, interpreted +** as an integer value, equal i. +** (Short version: This is an implementation of "on_control()"). +*/ + +int gfxop_set_visible_map(gfx_state_t *state, gfx_map_mask_t map); +/* Sets the currently visible map +** Parameters: (gfx_state_t *) state: The state to modify +** (gfx_map_mask_t) map: The GFX_MASK to set +** Returns : (int) GFX_OK, or GFX_ERROR if map was invalid +** 'visible_map' can be any of GFX_MASK_VISUAL, GFX_MASK_PRIORITY and GFX_MASK_CONTROL; the appropriate +** map (as far as its contents are known to the graphics subsystem) is then subsequently drawn to the +** screen at each update. If this is set to anything other than GFX_MASK_VISUAL, slow full-screen updates +** are performed. Mostly useful for debugging. +** The screen needs to be updated for the changes to take effect. +*/ + +int gfxop_set_clip_zone(gfx_state_t *state, rect_t zone); +/* Sets a new clipping zone +** Parameters: (gfx_state_t *) state: The affected state +** (rect_t) zone: The new clipping zone +** Returns : (int) GFX_OK +*/ + +/******************************/ +/* Generic drawing operations */ +/******************************/ + +int gfxop_draw_line(gfx_state_t *state, + Common::Point start, Common::Point end, gfx_color_t color, + gfx_line_mode_t line_mode, gfx_line_style_t line_style); +/* Renders a clipped line to the back buffer +** Parameters: (gfx_state_t *) state: The state affected +** (Common::Point) start: Starting point of the line +** (Common::Point) end: End point of the line +** (gfx_color_t) color: The color to use for drawing +** (gfx_line_mode_t) line_mode: Any valid line mode to use +** (gfx_line_style_t) line_style: The line style to use +** Returns : (int) GFX_OK or GFX_FATAL +*/ + +int gfxop_draw_rectangle(gfx_state_t *state, rect_t rect, gfx_color_t color, gfx_line_mode_t line_mode, + gfx_line_style_t line_style); +/* Draws a non-filled rectangular box to the back buffer +** Parameters: (gfx_state_t *) state: The affected state +** (rect_t) rect: The rectangular area the box is drawn to +** (gfx_color_t) color: The color the box is to be drawn in +** (gfx_line_mode_t) line_mode: The line mode to use +** (gfx_line_style_t) line_style: The line style to use for the box +** Returns : (int) GFX_OK or GFX_FATAL +** Boxes drawn in thin lines will surround the minimal area described by rect. +*/ + +int gfxop_draw_box(gfx_state_t *state, rect_t box, gfx_color_t color1, gfx_color_t color2, + gfx_box_shade_t shade_type); +/* Draws a filled box to the back buffer +** Parameters: (gfx_state_t *) state: The affected state +** (rect_t) box: The area to draw to +** (gfx_color_t) color1: The primary color to use for drawing +** (gfx_color_t) color2: The secondary color to draw in +** (gfx_box_shade_t) shade_type: The shading system to use +** (e.g. GFX_BOX_SHADE_FLAT) +** Returns : (int) GFX_OK or GFX_FATAL +** The draw mask, control, and priority values are derived from color1. +*/ + +int gfxop_fill_box(gfx_state_t *state, rect_t box, gfx_color_t color); +/* Fills a box in the back buffer with a specific color +** Parameters: (gfx_state_t *) state: The state to draw to +** (rect_t) box: The box to fill +** (gfx_color_t) color: The color to use for filling +** Returns : (int) GFX_OK or GFX_FATAL +** This is a simple wrapper function for gfxop_draw_box +*/ + +int gfxop_clear_box(gfx_state_t *state, rect_t box); +/* Copies a box from the static buffer to the back buffer +** Parameters: (gfx_state_t *) state: The affected state +** (rect_t) box: The box to propagate from the static buffer +** Returns : (int) GFX_OK or GFX_FATAL +*/ + + +int gfxop_update(gfx_state_t *state); +/* Updates all dirty rectangles +** Parameters: (gfx_state_t) *state: The relevant state +** Returns : (int) GFX_OK or GFX_FATAL if reported by the driver +** In order to track dirty rectangles, they must be enabled in the options. +** This function instructs the resource manager to free all tagged data +** on certain occasions (see gfxop_new_pic). +*/ + + +int gfxop_update_box(gfx_state_t *state, rect_t box); +/* Propagates a box from the back buffer to the front (visible) buffer +** Parameters: (gfx_state_t *) state: The affected state +** (rect_t) box: The box to propagate to the front buffer +** Returns : (int) GFX_OK or GFX_FATAL +** This function instructs the resource manager to free all tagged data +** on certain occasions (see gfxop_new_pic). +** When called with dirty rectangle management enabled, it will automatically +** propagate all dirty rectangles as well, UNLESS dirty frame accounting has +** been disabled explicitly. +*/ + +int gfxop_enable_dirty_frames(gfx_state_t *state); +/* Enables dirty frame accounting +** Parameters: (gfx_state_t *) state: The state dirty frame accounting is to be enabled in +** Returns : (int) GFX_OK or GFX_ERROR if state was invalid +** Dirty frame accounting is enabled by default. +*/ + +int gfxop_disable_dirty_frames(gfx_state_t *state); +/* Disables dirty frame accounting +** Parameters: (gfx_state_t *) state: The state dirty frame accounting is to be disabled in +** Returns : (int) GFX_OK or GFX_ERROR if state was invalid +*/ + + +/********************/ +/* Color operations */ +/********************/ + +int gfxop_set_color(gfx_state_t *state, gfx_color_t *color, int r, int g, int b, int a, + int priority, int control); +/* Maps an r/g/b value to a color and sets a gfx_color_t structure +** Parameters: (gfx_state_t *) state: The current state +** (gfx_color_t *) color: Pointer to the structure to write to +** (int x int x int) r,g,b: The red/green/blue color intensity values +** of the result color (0x00 (minimum) to 0xff (max)) +** If any of these values is less than zero, the +** resulting color will not affect the visual map when +** used for drawing +** (int) a: The alpha (transparency) value, with 0x00 meaning absolutely +** opaque and 0xff meaning fully transparent. Alpha blending support +** is optional for drivers, so these are the only two values that +** are guaranteed to work as intended. Any value in between them +** must guarantee the following opaqueness: +** opaqueness(x-1) >= opaqueness(x) >= opaqueness (x+1) +** (i.e. ([0,255], less-transparent-than) must define a partial order) +** (int) priority: The priority to use for drawing, or -1 for none +** (int) control: The control to use for drawing, or -1 to disable drawing to the +** control map +** Returns : (int) GFX_OK or GFX_ERROR if state is invalid +** In palette mode, this may allocate a new color. Use gfxop_free_color() described below to +** free that color. +*/ + +int gfxop_set_system_color(gfx_state_t *state, gfx_color_t *color); +/* Designates a color as a 'system color' +** Parameters: (gfx_state_t *) state: The affected state +** (gfx_color_t *) color: The color to designate as a system color +** Returns : (int) GFX_OK or GFX_ERROR if state is invalid +** System colors are permanent colors that cannot be deallocated. As such, they must be used +** with caution. +*/ + +int gfxop_free_color(gfx_state_t *state, gfx_color_t *color); +/* Frees a color allocated by gfxop_set_color() +** Parmaeters: (gfx_state_t *) state: The state affected +** (gfx_color_t *) color: The color to de-allocate +** Returns : (int) GFX_OK or GFX_ERROR if state is invalid +** This function is a no-op in non-index mode, or if color is a system color. +*/ + + +/**********************/ +/* Pointer and IO ops */ +/**********************/ + +int gfxop_usleep(gfx_state_t *state, long usecs); +/* Suspends program execution for the specified amount of microseconds +** Parameters: (gfx_state_t *) state: The state affected +** (long) usecs: The amount of microseconds to wait +** Returns : (int) GFX_OK or GFX_ERROR +** The mouse pointer will be redrawn continually, if applicable +*/ + +int gfxop_set_pointer_cursor(gfx_state_t *state, int nr); +/* Sets the mouse pointer to a cursor resource +** Parameters: (gfx_state_t *) state: The affected state +** (int) nr: Number of the cursor resource to use +** Returns : (int) GFX_OK, GFX_ERROR if the resource did not +** exist and was not GFXOP_NO_POINTER, or GFX_FATAL on +** fatal error conditions. +** Use nr = GFX_NO_POINTER to disable the mouse pointer (default). +*/ + +int gfxop_set_pointer_view(gfx_state_t *state, int nr, int loop, int cel, Common::Point *hotspot); +/* Sets the mouse pointer to a view resource +** Parameters: (gfx_state_t *) state: The affected state +** (int) nr: Number of the view resource to use +** (int) loop: View loop to use +** (int) cel: View cel to use +** (Common::Point *) hotspot: Manually set hotspot to use, or NULL for default. +** Returns : (int) GFX_OK or GFX_FATAL +** Use gfxop_set_pointer_cursor(state, GFXOP_NO_POINTER) to disable the +** pointer. +*/ + +int gfxop_set_pointer_position(gfx_state_t *state, Common::Point pos); +/* Teleports the mouse pointer to a specific position +** Parameters: (gfx_state_t *) state: The state the pointer is in +** (Common::Point) pos: The position to teleport it to +** Returns : (int) Any error code or GFX_OK +** Depending on the graphics driver, this operation may be without +** any effect +*/ + +sci_event_t gfxop_get_event(gfx_state_t *state, unsigned int mask); +/* Retreives the next input event from the driver +** Parameters: (gfx_state_t *) state: The affected state +** (int) mask: The event mask to poll from (see uinput.h) +** Returns : (sci_event_t) The next event in the driver's event queue, or +** a NONE event if no event matching the mask was found. +*/ + + +/*******************/ +/* View operations */ +/*******************/ + +int gfxop_lookup_view_get_loops(gfx_state_t *state, int nr); +/* Determines the number of loops associated with a view +** Parameters: (gfx_state_t *) state: The state to use +** (int) nr: Number of the view to investigate +** Returns : (int) The number of loops, or GFX_ERROR if the view didn't exist +*/ + +int gfxop_lookup_view_get_cels(gfx_state_t *state, int nr, int loop); +/* Determines the number of cels associated stored in a loop +** Parameters: (gfx_state_t *) state: The state to look up in +** (int) nr: Number of the view to look up in +** (int) loop: Number of the loop the number of cels of +** are to be investigated +** Returns : (int) The number of cels in that loop, or GFX_ERROR if either +** the view or the loop didn't exist +*/ + +int gfxop_check_cel(gfx_state_t *state, int nr, int *loop, int *cel); +/* Clips the view/loop/cel position of a cel +** Parameters: (gfx_state_t *) state: The state to use +** (int) nr: Number of the view to use +** (int *) loop: Pointer to the variable storing the loop +** number to verify +** (int *) cel: Pointer to the variable storing the cel +** number to check +** Returns : (int) GFX_OK or GFX_ERROR if the view didn't exist +** *loop is clipped first, then *cel. The resulting setup will be a valid +** view configuration. +*/ + +int gfxop_overflow_cel(gfx_state_t *state, int nr, int *loop, int *cel); +/* Resets loop/cel values to zero if they have become invalid +** Parameters: (gfx_state_t *) state: The state to use +** (int) nr: Number of the view to use +** (int *) loop: Pointer to the variable storing the loop +** number to verify +** (int *) cel: Pointer to the variable storing the cel +** number to check +** Returns : (int) GFX_OK or GFX_ERROR if the view didn't exist +** *loop is clipped first, then *cel. The resulting setup will be a valid +** view configuration. +*/ + +int gfxop_get_cel_parameters(gfx_state_t *state, int nr, int loop, int cel, + int *width, int *height, Common::Point *offset); +/* Retreives the width and height of a cel +** Parameters: (gfx_state_t *) state: The state to use +** (int) nr: Number of the view +** (int) loop: Loop number to examine +** (int) cel: The cel (inside the loop) to look up +** (int *) width: The variable the width will be stored in +** (int *) height: The variable the height will be stored in +** (Common::Point *) offset: The variable the cel's x/y offset will be stored in +** Returns : (int) GFX_OK if the lookup succeeded, GFX_ERROR if the nr/loop/cel +** combination was invalid +*/ + +int gfxop_draw_cel(gfx_state_t *state, int nr, int loop, int cel, Common::Point pos, + gfx_color_t color, int palette); +/* Draws (part of) a cel to the back buffer +** Parameters: (gfx_state_t *) state: The state encapsulating the driver to draw with +** (int) nr: Number of the view to draw +** (int) loop: Loop of the cel to draw +** (int) cel: The cel number of the cel to draw +** (Common::Point) pos: The positino the cel is to be drawn to +** (gfx_color_t color): The priority and control values to use for drawing +** (int) palette: The palette to use +** Returns : (int) GFX_OK or GFX_FATAL +*/ + + +int gfxop_draw_cel_static(gfx_state_t *state, int nr, int loop, int cel, Common::Point pos, + gfx_color_t color, int palette); +/* Draws a cel to the static buffer; no clipping is performed +** Parameters: (gfx_state_t *) state: The state encapsulating the driver to draw with +** (int) nr: Number of the view to draw +** (int) loop: Loop of the cel to draw +** (int) cel: The cel number of the cel to draw +** (Common::Point) pos: The positino the cel is to be drawn to +** (gfx_color_t color): The priority and control values to use for drawing +** (int) palette: The palette to use +** Returns : (int) GFX_OK or GFX_FATAL +** Let me repeat, no clipping (except for the display borders) is performed. +*/ + + +int gfxop_draw_cel_static_clipped(gfx_state_t *state, int nr, int loop, int cel, Common::Point pos, + gfx_color_t color, int palette); +/* Draws (part of) a clipped cel to the static buffer +** Parameters: (gfx_state_t *) state: The state encapsulating the driver to draw with +** (int) nr: Number of the view to draw +** (int) loop: Loop of the cel to draw +** (int) cel: The cel number of the cel to draw +** (Common::Point) pos: The positino the cel is to be drawn to +** (gfx_color_t color): The priority and control values to use for drawing +** (int) palette: The palette to use +** Returns : (int) GFX_OK or GFX_FATAL +** This function does clip. +*/ + + +/******************/ +/* Pic operations */ +/******************/ +/* These operations are exempt from clipping */ + +int gfxop_new_pic(gfx_state_t *state, int nr, int flags, int default_palette); +/* Draws a pic and writes it over the static buffer +** Parameters: (gfx_state_t *) state: The state affected +** (int) nr: Number of the pic to draw +** (int) flags: Interpreter-dependant flags to use for drawing +** (int) default_palette: The default palette for drawing +** Returns : (int) GFX_OK or GFX_FATAL +** This function instructs the resource manager to tag all data as "unused". +** See the resource manager tag functions for a full description. +*/ + +void *gfxop_get_pic_metainfo(gfx_state_t *state); +/* Retreives all meta-information assigned to the current pic +** Parameters: (gfx_state_t *) state: The state affected +** Returns : (void *) NULL if the pic doesn't exist or has no meta-information, +** the meta-info otherwise +** This meta-information is referred to as 'internal data' in the pic code +*/ + +int gfxop_add_to_pic(gfx_state_t *state, int nr, int flags, int default_palette); +/* Adds a pic to the static buffer +** Parameters: (gfx_state_t *) state: The state affected +** (int) nr: Number of the pic to add +** (int) flags: Interpreter-dependant flags to use for drawing +** (int) default_palette: The default palette for drawing +** Returns : (int) GFX_OK or GFX_FATAL +*/ + + + + +/*******************/ +/* Text operations */ +/*******************/ + + +int gfxop_get_font_height(gfx_state_t *state, int font_nr); +/* Returns the fixed line height for one specified font +** Parameters: (gfx_state_t *) state: The state to work on +** (int) font_nr: Number of the font to inspect +** Returns : (int) GFX_ERROR, GFX_FATAL, or the font line height +*/ + +int gfxop_get_text_params(gfx_state_t *state, int font_nr, const char *text, + int maxwidth, int *width, int *height, int flags, + int *lines_nr, int *lineheight, int *lastline_width); +/* Calculates the width and height of a specified text in a specified font +** Parameters: (gfx_state_t *) state: The state to use +** (int) font_nr: Font number to use for the calculation +** (const char *) text: The text to examine +** (int) flags: ORred GFXR_FONT_FLAGs +** (int) maxwidth: The maximum pixel width to allow for the text +** Returns : (int) GFX_OK or GFX_ERROR if the font didn't exist +** (int) *width: The resulting width +** (int) *height: The resulting height +** (int) *lines_nr: Number of lines used in the text +** (int) *lineheight: Pixel height (SCI scale) of each text line +** (int) *lastline_wdith: Pixel offset (SCI scale) of the space +** after the last character in the last line +*/ + +gfx_text_handle_t *gfxop_new_text(gfx_state_t *state, int font_nr, char *text, int maxwidth, + gfx_alignment_t halign, gfx_alignment_t valign, gfx_color_t color1, + gfx_color_t color2, gfx_color_t bg_color, int flags); +/* Generates a new text handle that can be used to draw any text +** Parameters: (gfx_state_t *) state: The state to use +** (int) font_nr: Font number to use for the calculation +** (char *) text: The text to examine +** (int) maxwidth: The maximum pixel width to allow for the text +** (gfx_alignment_t) halign: The horizontal text alignment +** (gfx_alignment_t) valign: The vertical text alignment +** (gfx_color_t x gfx_color_t) color1, color2: The text's foreground colors +** (the function will dither between those two) +** (gfx_color_t) bg_color: The background color +** (int) flags: ORred GFXR_FONT_FLAGs +** Returns : (gfx_text_handle_t *) A newly allocated gfx_text_handle_t, or +** NULL if font_nr was invalid +** The control and priority values for the text will be extracted from color1. +** Note that the colors must have been allocated properly, or the text may display in +** incorrect colors. +*/ + +int gfxop_free_text(gfx_state_t *state, gfx_text_handle_t *handle); +/* Frees a previously allocated text handle and all related resources +** Parameters: (gfx_state_t *) state: The state to use +** (gfx_text_handle_t *) handle: The handle to free +** Returns : (int) GFX_OK +*/ + +int gfxop_draw_text(gfx_state_t *state, gfx_text_handle_t *handle, rect_t zone); +/* Draws text stored in a text handle +** Parameters: (gfx_state_t *) state: The target state +** (gfx_text_handle_t *) handle: The text handle to use for drawing +** (rect_t) zone: The rectangular box to draw to. In combination with +** halign and valign, this defines where the text is +** drawn to. +** Returns : (int) GFX_OK or GFX_FATAL +*/ + + +/****************************/ +/* Manual pixmap operations */ +/****************************/ + +gfx_pixmap_t *gfxop_grab_pixmap(gfx_state_t *state, rect_t area); +/* Grabs a screen section from the back buffer and stores it in a pixmap +** Parameters: (gfx_state_t *) state: The affected state +** (rect_t) area: The area to grab +** Returns : (gfx_pixmap_t *) A result pixmap, or NULL on error +** Obviously, this only affects the visual map +*/ + +int gfxop_draw_pixmap(gfx_state_t *state, gfx_pixmap_t *pxm, rect_t zone, Common::Point pos); +/* Draws part of a pixmap to the screen +** Parameters: (gfx_state_t *) state: The affected state +** (gfx_pixmap_t *) pxm: The pixmap to draw +** (rect_t) zone: The segment of the pixmap to draw +** (Common::Point) pos: The position the pixmap should be drawn to +** Returns : (int) GFX_OK or any error code +*/ + +int gfxop_free_pixmap(gfx_state_t *state, gfx_pixmap_t *pxm); +/* Frees a pixmap returned by gfxop_grab_pixmap() +** Parameters: (gfx_state_t *) state: The affected state +** (gfx_pixmap_t *) pxm: The pixmap to free +** Returns : (int) GFX_OK, or GFX_ERROR if the state was invalid +*/ + +/******************************/ +/* Dirty rectangle operations */ +/******************************/ + +gfx_dirty_rect_t *gfxdr_add_dirty(gfx_dirty_rect_t *base, rect_t box, int strategy); +/* Adds a dirty rectangle to 'base' according to a strategy +** Parameters: (gfx_dirty_rect_t *) base: The base rectangle to add to, or NULL +** (rect_t) box: The dirty frame to add +** (int) strategy: The dirty frame heuristic to use (see gfx_options.h) +** Returns : (gfx_dirty_rect_t *) an appropriate singly-linked dirty rectangle +** result cluster +*/ + +int _gfxop_clip(rect_t *rect, rect_t clipzone); +/* Clips a rectangle against another one +** Parameters: (rect_t *) rect: The rectangle to clip +** (rect_t) clipzone: The outer bounds rect must be in +** Reuturns : (int) 1 if rect is empty now, 0 otherwise +*/ + +} // End of namespace Sci + +#endif // SCI_GFX_GFX_OPERATIONS_H diff --git a/engines/sci/gfx/sci_widgets.cpp b/engines/sci/gfx/sci_widgets.cpp index 398f315285..d6ab47b4d2 100644 --- a/engines/sci/gfx/sci_widgets.cpp +++ b/engines/sci/gfx/sci_widgets.cpp @@ -23,11 +23,11 @@ * */ -#include "sci/gfx/gfx_operations.h" +#include "sci/gfx/operations.h" #include "sci/gfx/gfx_widgets.h" #include "sci/include/engine.h" #include "sci/gfx/menubar.h" -#include "sci/include/sci_widgets.h" +#include "sci/gfx/sci_widgets.h" #include "common/system.h" diff --git a/engines/sci/gfx/sci_widgets.h b/engines/sci/gfx/sci_widgets.h new file mode 100644 index 0000000000..ea7199dcc1 --- /dev/null +++ b/engines/sci/gfx/sci_widgets.h @@ -0,0 +1,205 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* SCI-specific widget handling */ + +#ifndef SCI_INCLUDE_SCI_WIDGETS_H +#define SCI_INCLUDE_SCI_WIDGETS_H + +#include "sci/include/engine.h" + +namespace Sci { + +struct menu_t; + +/* The following flags are applicable to windows in SCI0: */ +#define WINDOW_FLAG_TRANSPARENT 0x01 + + +#define WINDOW_FLAG_NOFRAME 0x02 +/* No frame is drawn around the window onto wm_view */ + +#define WINDOW_FLAG_TITLE 0x04 +/* Add titlebar to window (10 pixels high, framed, text is centered and written +** in white on dark gray +*/ + +#define WINDOW_FLAG_DONTDRAW 0x80 +/* Don't draw anything */ + +#define WINDOW_FLAG_NO_DROP_SHADOW 0x1000000 + + +/* Used in kgraphics to flag text surrounded by a dithered frame */ +#define CONTROL_STATE_DITHER_FRAMED 0x1000 + +/* Used by the interpreter to flag buttons that are grayed out */ +#define CONTROL_STATE_GRAY 0x0004 +/* Used by the interpreter to flag some widgets to determine whether they should be surrounded by a frame */ +#define CONTROL_STATE_FRAMED 0x0008 +/* Used by the interpreter to flag buttons that are enabled */ +#define CONTROL_STATE_ENABLED 0x0001 + +void sciw_set_status_bar(EngineState *s, gfxw_port_t *status_bar, char *text, int fgcolor, int bgcolor); +/* Sets the contents of a port used as status bar +** Parmeters: (EngineState *) s: The affected game state +** (gfxw_port_t *) status_bar: The status bar port +** (char *) text: The text to draw +** Returns : (void) +*/ + +gfxw_port_t *sciw_new_window(EngineState *s, rect_t area, int font, gfx_color_t color, gfx_color_t bgcolor, + int title_font, gfx_color_t title_color, gfx_color_t title_bg_color, + const char *title, int flags); +/* Creates a new SCI style window +** Parameters: (EngineState *) s: The affected game state +** (rect_t) area: The screen area to frame (not including a potential window title) +** (int) font: Default font number to use +** (gfx_color_t) color: The foreground color to use for drawing +** (gfx_color_t) bgcolor: The background color to use +** (int) title_font: The font to use for the title bar (if any) +** (gfx_color_t) title_color: Color to use for the title bar text +** (gfx_color_t) title_bg_color: Color to use for the title bar background +** (const char *) title: The text to write into the title bar +** (int) flags: Any ORred combination of window flags +** Returns : (gfxw_port_t *) A newly allocated port with the requested characteristics +*/ + +/*---------------------*/ +/*** Control widgets ***/ +/*---------------------*/ + +gfxw_list_t *sciw_new_button_control(gfxw_port_t *port, reg_t ID, rect_t zone, char *text, int font, char selected, char inverse, char gray); +/* Creates a new button control list +** Parameters: (gfxw_port_t *) port: The port containing the color values to use for the +** button (the button is /not/ appended to the port there) +** (reg_t) ID: Button's ID +** (rect_t) zone: The area occupied by the button +** (char *) text: The text to write into the button +** (int) font: The font to use for the button +** (char) selected: Whether the button should be marked as being selected by the keyboard focus +** (char) inverse: Whether to inverse the color scheme +** (char) gray: Whether the button should be grayed out +** Returns : (gfxw_list_t *) The button +*/ + +gfxw_list_t *sciw_new_text_control(gfxw_port_t *port, reg_t ID, rect_t zone, char *text, int font, + gfx_alignment_t align, char frame, char inverse); +/* Creates a new text control list +** Parameters: (gfxw_port_t *) port: The port containing the color values to use +** (reg_t) ID: Text widget ID +** (rect_t) zone: Area occupied by the text +** (char *) text: The text +** (int) font: The font the text is to be drawn in +** (gfx_alignment_t) align: Horizontal text alignment to use +** (char) frame: Whether a dithered frame should surround the text +** (char) inverse: Whether the text colors should be inversed +** Returns : (gfxw_list_t *) The text control widget list +*/ + +gfxw_list_t *sciw_new_edit_control(gfxw_port_t *port, reg_t ID, rect_t zone, char *text, int font, unsigned int cursor, + char inverse); +/* Creates a new edit control list +** Parameters: (gfxw_port_t *) port: The port containing the color values to use +** (reg_t) ID: Text widget ID +** (rect_t) zone: Area occupied by the text +** (char *) text: The text +** (int) font: The font the text is to be drawn in +** (int) cursor: Cursor position +** (char) inverse: Whether the edit widget should be reversed +** Returns : (gfxw_list_t *) An appropriate widget list +*/ + +gfxw_list_t *sciw_new_icon_control(gfxw_port_t *port, reg_t ID, rect_t zone, int view, int loop, int cel, + char frame, char inverse); +/* Creates a new icon control list +** Parameters: (gfxw_port_t *) port: The port containing the color values to use +** (reg_t) ID: Text widget ID +** (rect_t) zone: Area occupied by the text +** (int x int x int) view, loop, cel: The cel to display +** (char) frame: Whether the widget should be surrounded by a frame +** (char) lina inverse: Whether colors should be inversed +** Returns : (gfxw_list_t *) An appropriate widget list +*/ + +gfxw_list_t *sciw_new_list_control(gfxw_port_t *port, reg_t ID, rect_t zone, int font_nr, char **entries_list, + int entries_nr, int list_top, int selection, char inverse); +/* Creates a new list control list +** Parameters: (gfxw_port_t *) port: The port containing the color values to use +** (int) ID: Text widget ID +** (rect_t) zone: Area occupied by the text +** (int) font_nr: number of the font to use +** (char **) entries_list: List of strings to contain within the list +** (int) entries_nr: Number of entries in entries_list +** (int) list_top: First list item that is visible +** (int) selection: The list item that is selected +** (char) invserse: The usual meaning +** Returns : (gfxw_list_t *) An appropriate widget list +*/ + +/*---------------------*/ +/*** Menubar widgets ***/ +/*---------------------*/ + +void sciw_set_menubar(EngineState *s, gfxw_port_t *status_bar, menubar_t *menubar, int selection); +/* Draws the menu bar +** Parameters: (EngineState *) s: The state to operate on +** (gfxw_port_t *) status_bar: The status bar port to modify +** (menubar_t *) menubar: The menu bar to use +** (int) selection: Number of the menu to hightlight, or -1 for 'none' +** Returns : (void) +*/ + +gfxw_port_t *sciw_new_menu(EngineState *s, gfxw_port_t *status_bar, menubar_t *menubar, int selection); +/* Creates a menu port +** Parameters: (EngineState *) s: The state to operate on +** (gfxw_port_t *) status_bar: The status bar +** (menubar_t *) menubar: The menu bar to use +** (int) selection: Number of the menu to interpret +** Returns : (gfxw_port_t *) The result port +*/ + +gfxw_port_t *sciw_unselect_item(EngineState *s, gfxw_port_t *menu_port, menu_t *menu, int selection); +/* Unselects a previously selected item from a menu port +** Parameters: (EngineState *) s: The state to operate on +** (gfxw_port_t *) menu_port: The port modify +** (menu_t *) menu: The menu the menu port corresponds to +** (int) selection: Number of the menu entry to unselect, or -1 to do a NOP +** Returns : (gfxw_port_t *) The modified menu +*/ + +gfxw_port_t * +sciw_select_item(EngineState *s, gfxw_port_t *menu_port, menu_t *menu, int selection); +/* Selects a menu item from a menu port +** Parameters: (EngineState *) s: The state to operate on +** (gfxw_port_t *) menu_port: The port modify +** (menu_t *) menu: The menu the menu port corresponds to +** (int) selection: Number of the menu entry to select, or -1 to do a NOP +** Returns : (gfxw_port_t *) The modified menu +*/ + +} // End of namespace Sci + +#endif // SCI_INCLUDE_SCI_WIDGETS_H diff --git a/engines/sci/gfx/widgets.cpp b/engines/sci/gfx/widgets.cpp deleted file mode 100644 index 02bf37b314..0000000000 --- a/engines/sci/gfx/widgets.cpp +++ /dev/null @@ -1,2154 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "sci/sci_memory.h" -#include "sci/gfx/gfx_widgets.h" - -namespace Sci { - -#undef GFXW_DEBUG_DIRTY // Enable to debug dirty rectangle propagation (writes to stderr) - -#ifdef GFXW_DEBUG_DIRTY -# define DDIRTY fprintf(stderr, "%s:%5d| ", __FILE__, __LINE__); fprintf -#else -# define DDIRTY if (0) fprintf -#endif - -Common::Point gfxw_point_zero(0, 0); - -#define MAX_SERIAL_NUMBER 0x7fffffff -static int widget_serial_number_counter = 0x10000; // Avoid confusion with IDs - -#ifdef GFXW_DEBUG_WIDGETS - -gfxw_widget_t *debug_widgets[GFXW_DEBUG_WIDGETS]; -int debug_widget_pos = 0; - -static void _gfxw_debug_add_widget(gfxw_widget_t *widget) { - if (debug_widget_pos == GFXW_DEBUG_WIDGETS) { - GFXERROR("WIDGET DEBUG: Allocated the maximum number of %d widgets- Aborting!\n", GFXW_DEBUG_WIDGETS); - BREAKPOINT(); - } - debug_widgets[debug_widget_pos++] = widget; -} - -static void _gfxw_debug_remove_widget(gfxw_widget_t *widget) { - int i; - int found = 0; - for (i = 0; i < debug_widget_pos; i++) { - if (debug_widgets[i] == widget) { - memmove(debug_widgets + i, debug_widgets + i + 1, (sizeof(gfxw_widget_t *)) * (debug_widget_pos - i - 1)); - debug_widgets[debug_widget_pos--] = NULL; - found++; - } - } - - if (found > 1) { - GFXERROR("While removing widget: Found it %d times!\n", found); - BREAKPOINT(); - } - - if (found == 0) { - GFXERROR("Attempted removal of unregistered widget!\n"); - BREAKPOINT(); - } -} -#else // !GFXW_DEBUG_WIDGETS -#define _gfxw_debug_add_widget(a) -#define _gfxw_debug_remove_widget(a) -#endif - - -static inline void indent(int indentation) { - int i; - for (i = 0; i < indentation; i++) - sciprintf(" "); -} - -static void _gfxw_print_widget(gfxw_widget_t *widget, int indentation) { - unsigned int i; - char flags_list[] = "VOCDTMI"; - - indent(indentation); - - if (widget->magic == GFXW_MAGIC_VALID) { - if (widget->visual) - sciprintf("v "); - else - sciprintf("NoVis "); - } else if (widget->magic == GFXW_MAGIC_INVALID) - sciprintf("INVALID "); - - sciprintf("S%08x", widget->serial); - - if (widget->ID != GFXW_NO_ID) { - sciprintf("#%x", widget->ID); - - if (widget->subID != GFXW_NO_ID) - sciprintf(":%x ", widget->subID); - else - sciprintf(" "); - } - - sciprintf("[(%d,%d)(%dx%d)]", widget->bounds.x, widget->bounds.y, widget->bounds.xl, widget->bounds.yl); - - for (i = 0; i < strlen(flags_list); i++) - if (widget->flags & (1 << i)) - sciprintf("%c", flags_list[i]); - - sciprintf(" "); -} - -static int _gfxwop_print_empty(gfxw_widget_t *widget, int indentation) { - _gfxw_print_widget(widget, indentation); - sciprintf("", widget->type); - - return 0; -} - -gfxw_widget_t * _gfxw_new_widget(int size, gfxw_widget_type_t type) { - gfxw_widget_t *widget = (gfxw_widget_t*)sci_malloc(size); -#ifdef SATISFY_PURIFY - memset(widget, 0, size); -#endif - - widget->magic = GFXW_MAGIC_VALID; - widget->parent = NULL; - widget->visual = NULL; - widget->next = NULL; - widget->type = type; - widget->bounds = gfx_rect(0, 0, 0, 0); - widget->flags = GFXW_FLAG_DIRTY; - widget->ID = GFXW_NO_ID; - widget->subID = GFXW_NO_ID; - widget->serial = widget_serial_number_counter++; - widget->widget_priority = -1; - - widget_serial_number_counter &= MAX_SERIAL_NUMBER; - - widget->draw = NULL; - widget->widfree = NULL; - widget->tag = NULL; - widget->print = _gfxwop_print_empty; - widget->should_replace = NULL; - widget->compare_to = widget->equals = widget->superarea_of = NULL; - - _gfxw_debug_add_widget(widget); - - return widget; -} - -static inline int verify_widget(gfxw_widget_t *widget) { - if (!widget) { - GFXERROR("Attempt to use NULL widget\n"); -#ifdef GFXW_DEBUG_WIDGETS - BREAKPOINT(); -#endif - return 1; - } else if (widget->magic != GFXW_MAGIC_VALID) { - if (widget->magic == GFXW_MAGIC_INVALID) { - GFXERROR("Attempt to use invalidated widget\n"); - } else { - GFXERROR("Attempt to use non-widget\n"); - } -#ifdef GFXW_DEBUG_WIDGETS - BREAKPOINT(); -#endif - return 1; - } - return 0; -} - -#define VERIFY_WIDGET(w) \ - if (verify_widget((gfxw_widget_t *)(w))) { GFXERROR("Error occured while validating widget\n"); } - -static void _gfxw_unallocate_widget(gfx_state_t *state, gfxw_widget_t *widget) { - if (GFXW_IS_TEXT(widget)) { - gfxw_text_t *text = (gfxw_text_t *) widget; - - if (text->text_handle) { - if (!state) { - GFXERROR("Attempt to free text without supplying mode to free it from!\n"); - BREAKPOINT(); - } else { - gfxop_free_text(state, text->text_handle); - text->text_handle = NULL; - } - } - } - - widget->magic = GFXW_MAGIC_INVALID; - free(widget); - _gfxw_debug_remove_widget(widget); -} - -#define GFX_ASSERT(_x) \ -{ \ - int retval = (_x); \ - if (retval == GFX_ERROR) { \ - GFXERROR("Error occured while drawing widget!\n"); \ - return 1; \ - } else if (retval == GFX_FATAL) { \ - error("Fatal error occured while drawing widget!\nGraphics state invalid; aborting program..."); \ - } \ -} - -//********** Widgets ************* - -// Base class operations and common stuff - -// Assertion for drawing -#define DRAW_ASSERT(widget, exp_type) \ - if (!(widget)) { \ - sciprintf("L%d: NULL widget", __LINE__); \ - return 1; \ - } \ - if (!(widget)->print) { \ - sciprintf("L%d: Widget of type %d does not have print function", __LINE__, (widget)->type); \ - } \ - if ((widget)->type != (exp_type)) { \ - sciprintf("L%d: Error in widget: Expected type " # exp_type "(%d) but got %d\n", __LINE__, exp_type, (widget)->type); \ - sciprintf("Erroneous widget: "); \ - widget->print(widget, 4); \ - sciprintf("\n"); \ - return 1; \ - } \ - if (!(widget->flags & GFXW_FLAG_VISIBLE)) \ - return 0; \ - if (!(widget->type == GFXW_VISUAL || widget->visual)) { \ - sciprintf("L%d: Error while drawing widget: Widget has no visual\n", __LINE__); \ - sciprintf("Erroneous widget: "); \ - widget->print(widget, 1); \ - sciprintf("\n"); \ - return 1; \ - } - -static inline int _color_equals(gfx_color_t a, gfx_color_t b) { - if (a.mask != b.mask) - return 0; - - if (a.mask & GFX_MASK_VISUAL) { - if (a.visual.r != b.visual.r || a.visual.g != b.visual.g || a.visual.b != b.visual.b || a.alpha != b.alpha) - return 0; - } - - if (a.mask & GFX_MASK_PRIORITY) - if (a.priority != b.priority) - return 0; - - if (a.mask & GFX_MASK_CONTROL) - if (a.control != b.control) - return 0; - - return 1; -} - -static int _gfxwop_basic_set_visual(gfxw_widget_t *widget, gfxw_visual_t *visual) { - widget->visual = visual; - - if (widget->parent) { - DDIRTY(stderr, "basic_set_visual: DOWNWARDS rel(%d,%d,%d,%d, 1)\n", GFX_PRINT_RECT(widget->bounds)); - widget->parent->add_dirty_rel(widget->parent, widget->bounds, 1); - } - - return 0; -} - -static int _gfxwop_basic_should_replace(gfxw_widget_t *widget, gfxw_widget_t *other) { - return 0; -} - -static inline void _gfxw_set_ops(gfxw_widget_t *widget, gfxw_point_op *draw, gfxw_op *free, gfxw_op *tag, gfxw_op_int *print, - gfxw_bin_op *compare_to, gfxw_bin_op *equals, gfxw_bin_op *superarea_of) { - widget->draw = draw; - widget->widfree = free; - widget->tag = tag; - widget->print = print; - widget->compare_to = compare_to; - widget->equals = equals; - widget->superarea_of = superarea_of; - - widget->should_replace = _gfxwop_basic_should_replace; - widget->set_visual = _gfxwop_basic_set_visual; -} - -void gfxw_remove_widget_from_container(gfxw_container_t *container, gfxw_widget_t *widget) { - gfxw_widget_t **seekerp; - - if (!container) { - GFXERROR("Attempt to remove widget from NULL container!\n"); - BREAKPOINT(); - } - - seekerp = &(container->contents); - - if (GFXW_IS_LIST(widget) && GFXW_IS_PORT(container)) { - gfxw_port_t *port = (gfxw_port_t *) container; - if (port->decorations == (gfxw_list_t *) widget) { - port->decorations = NULL; - return; - } - } - - while (*seekerp && *seekerp != widget) - seekerp = &((*seekerp)->next); - - if (!*seekerp) { - GFXERROR("Internal error: Attempt to remove widget from container it was not contained in!\n"); - sciprintf("Widget:"); - widget->print(GFXW(widget), 1); - sciprintf("Container:"); - widget->print(GFXW(container), 1); - BREAKPOINT(); - return; - } - - if (container->nextpp == &(widget->next)) - container->nextpp = seekerp; - - *seekerp = widget->next; // Remove it - widget->parent = NULL; - widget->next = NULL; -} - -static int _gfxwop_basic_free(gfxw_widget_t *widget) { - gfxw_visual_t *visual = widget->visual; - gfx_state_t *state = (visual) ? visual->gfx_state : NULL; - - DDIRTY(stderr, "BASIC-FREE: SomeAddDirty\n"); - - if (widget->parent) { - if (GFXW_IS_CONTAINER(widget)) - widget->parent->add_dirty_abs(widget->parent, widget->bounds, 1); - else - widget->parent->add_dirty_rel(widget->parent, widget->bounds, 1); - - gfxw_remove_widget_from_container(widget->parent, widget); - } - - _gfxw_unallocate_widget(state, widget); - - return 0; -} - -static int _gfxwop_basic_tag(gfxw_widget_t *widget) { - widget->flags |= GFXW_FLAG_TAGGED; - - return 0; -} - -static int _gfxwop_basic_compare_to(gfxw_widget_t *widget, gfxw_widget_t *other) { - return 1; -} - -static int _gfxwop_basic_equals(gfxw_widget_t *widget, gfxw_widget_t *other) { - return 0; -} - -static int _gfxwop_basic_superarea_of(gfxw_widget_t *widget, gfxw_widget_t *other) { - return (widget == other); -} - -//*** Boxes *** - -static inline rect_t _move_rect(rect_t rect, Common::Point point) { - return gfx_rect(rect.x + point.x, rect.y + point.y, rect.xl, rect.yl); -} - -static inline void _split_rect(rect_t rect, Common::Point *p1, Common::Point *p2) { - p1->x = rect.x; - p1->y = rect.y; - p2->x = rect.x + rect.xl; - p2->y = rect.y + rect.yl; -} - -static inline Common::Point _move_point(rect_t rect, Common::Point point) { - return Common::Point(rect.x + point.x, rect.y + point.y); -} - -static int _gfxwop_box_draw(gfxw_widget_t *widget, Common::Point pos) { - gfxw_box_t *box = (gfxw_box_t *) widget; - DRAW_ASSERT(widget, GFXW_BOX); - GFX_ASSERT(gfxop_draw_box(box->visual->gfx_state, _move_rect(box->bounds, pos), box->color1, box->color2, box->shade_type)); - - return 0; -} - -static int _gfxwop_box_print(gfxw_widget_t *widget, int indentation) { - _gfxw_print_widget(widget, indentation); - sciprintf("BOX"); - return 0; -} - -static int _gfxwop_box_superarea_of(gfxw_widget_t *widget, gfxw_widget_t *other) { - gfxw_box_t *box = (gfxw_box_t *) widget; - - if (box->color1.alpha) - return 0; - - if (box->shade_type != GFX_BOX_SHADE_FLAT && box->color2.alpha) - return 0; - - if (!gfx_rect_subset(other->bounds, box->bounds)) - return 0; - - return 1; -} - -static int _gfxwop_box_equals(gfxw_widget_t *widget, gfxw_widget_t *other) { - gfxw_box_t *wbox = (gfxw_box_t *)widget, *obox; - if (other->type != GFXW_BOX) - return 0; - - obox = (gfxw_box_t *) other; - - if (!gfx_rect_equals(wbox->bounds, obox->bounds)) - return 0; - - if (!_color_equals(wbox->color1, obox->color1)) - return 0; - - if (wbox->shade_type != obox->shade_type) - return 0; - - if (wbox->shade_type != GFX_BOX_SHADE_FLAT - && _color_equals(wbox->color2, obox->color2)) - return 0; - - return 1; -} - -void _gfxw_set_ops_BOX(gfxw_widget_t *widget) { - _gfxw_set_ops(GFXW(widget), _gfxwop_box_draw, _gfxwop_basic_free, _gfxwop_basic_tag, _gfxwop_box_print, - _gfxwop_basic_compare_to, _gfxwop_box_equals, _gfxwop_box_superarea_of); -} - -static inline int _gfxw_color_get_priority(gfx_color_t color) { - return (color.mask & GFX_MASK_PRIORITY) ? color.priority : -1; -} - -gfxw_box_t *gfxw_new_box(gfx_state_t *state, rect_t area, gfx_color_t color1, gfx_color_t color2, gfx_box_shade_t shade_type) { - gfxw_box_t *widget = (gfxw_box_t *)_gfxw_new_widget(sizeof(gfxw_box_t), GFXW_BOX); - - widget->widget_priority = _gfxw_color_get_priority(color1); - widget->bounds = area; - widget->color1 = color1; - widget->color2 = color2; - widget->shade_type = shade_type; - - widget->flags |= GFXW_FLAG_VISIBLE; - - if ((color1.mask & GFX_MASK_VISUAL) && ((state && (state->driver->mode->palette)) || (!color1.alpha && !color2.alpha))) - widget->flags |= GFXW_FLAG_OPAQUE; - - _gfxw_set_ops_BOX(GFXW(widget)); - - return widget; -} - -static inline gfxw_primitive_t *_gfxw_new_primitive(rect_t area, gfx_color_t color, gfx_line_mode_t mode, - gfx_line_style_t style, gfxw_widget_type_t type) { - gfxw_primitive_t *widget = (gfxw_primitive_t *)_gfxw_new_widget(sizeof(gfxw_primitive_t), type); - - widget->widget_priority = _gfxw_color_get_priority(color); - widget->bounds = area; - widget->color = color; - widget->line_mode = mode; - widget->line_style = style; - - widget->flags |= GFXW_FLAG_VISIBLE; - return widget; -} - -//*** Rectangles *** - -static int _gfxwop_primitive_equals(gfxw_widget_t *widget, gfxw_widget_t *other) { - gfxw_primitive_t *wprim = (gfxw_primitive_t *) widget, *oprim; - if (widget->type != other->type) - return 0; - - oprim = (gfxw_primitive_t *) other; - - if (!gfx_rect_equals(wprim->bounds, oprim->bounds)) - return 0; - - if (!_color_equals(wprim->color, oprim->color)) - return 0; - - if (wprim->line_mode != oprim->line_mode) - return 0; - - if (wprim->line_style != oprim->line_style) - return 0; - - return 1; -} - -static int _gfxwop_rect_draw(gfxw_widget_t *widget, Common::Point pos) { - gfxw_primitive_t *rect = (gfxw_primitive_t *) widget; - DRAW_ASSERT(widget, GFXW_RECT); - - GFX_ASSERT(gfxop_draw_rectangle(rect->visual->gfx_state, gfx_rect(rect->bounds.x + pos.x, rect->bounds.y + pos.y, - rect->bounds.xl - 1, rect->bounds.yl - 1), rect->color, rect->line_mode, rect->line_style)); - return 0; -} - -static int _gfxwop_rect_print(gfxw_widget_t *rect, int indentation) { - _gfxw_print_widget(GFXW(rect), indentation); - sciprintf("RECT"); - - return 0; -} - -void _gfxw_set_ops_RECT(gfxw_widget_t *prim) { - _gfxw_set_ops(GFXW(prim), _gfxwop_rect_draw, _gfxwop_basic_free, _gfxwop_basic_tag, _gfxwop_rect_print, - _gfxwop_basic_compare_to, _gfxwop_primitive_equals, _gfxwop_basic_superarea_of); -} - -gfxw_primitive_t *gfxw_new_rect(rect_t rect, gfx_color_t color, gfx_line_mode_t line_mode, gfx_line_style_t line_style) { - gfxw_primitive_t *prim = _gfxw_new_primitive(rect, color, line_mode, line_style, GFXW_RECT); - prim->bounds.xl++; - prim->bounds.yl++; // Since it is actually one pixel bigger in each direction - - _gfxw_set_ops_RECT(GFXW(prim)); - - return prim; -} - -//*** Lines *** - -static int _gfxwop_line_draw(gfxw_widget_t *widget, Common::Point pos) { - gfxw_primitive_t *line = (gfxw_primitive_t *)widget; - rect_t linepos = widget->bounds; - Common::Point p1, p2; - - linepos.xl--; - linepos.yl--; - - if (widget->type == GFXW_INVERSE_LINE) { - linepos.x += linepos.xl; - linepos.xl = -linepos.xl; - } else { - DRAW_ASSERT(widget, GFXW_LINE); - } - - _split_rect(_move_rect(linepos, pos), &p1, &p2); - GFX_ASSERT(gfxop_draw_line(line->visual->gfx_state, p1, p2, line->color, line->line_mode, line->line_style)); - return 0; -} - -static int _gfxwop_line_print(gfxw_widget_t *widget, int indentation) { - _gfxw_print_widget(widget, indentation); - if (widget->type == GFXW_INVERSE_LINE) - sciprintf("INVERSE-LINE"); - else - sciprintf("LINE"); - - return 0; -} - -void _gfxw_set_ops_LINE(gfxw_widget_t *prim) { - _gfxw_set_ops(GFXW(prim), _gfxwop_line_draw, _gfxwop_basic_free, _gfxwop_basic_tag, _gfxwop_line_print, - _gfxwop_basic_compare_to, _gfxwop_primitive_equals, _gfxwop_basic_superarea_of); -} - -gfxw_primitive_t *gfxw_new_line(Common::Point start, Common::Point end, gfx_color_t color, gfx_line_mode_t line_mode, gfx_line_style_t line_style) { - gfxw_primitive_t *prim; - // Encode into internal representation - rect_t line = gfx_rect(start.x, start.y, end.x - start.x, end.y - start.y); - - byte inverse = 0; - - if (line.xl < 0) { - line.x += line.xl; - line.y += line.yl; - line.xl = -line.xl; - line.yl = -line.yl; - } - - if (line.yl < 0) { - inverse = 1; - line.x += line.xl; - line.xl = -line.xl; - } - - line.xl++; - line.yl++; - - prim = _gfxw_new_primitive(line, color, line_mode, line_style, inverse ? GFXW_INVERSE_LINE : GFXW_LINE); - - _gfxw_set_ops_LINE(GFXW(prim)); - - return prim; -} - -//*** Views and static views *** - -gfxw_view_t *_gfxw_new_simple_view(gfx_state_t *state, Common::Point pos, int view, int loop, int cel, int palette, int priority, int control, - gfx_alignment_t halign, gfx_alignment_t valign, int size, gfxw_widget_type_t type) { - gfxw_view_t *widget; - int width, height; - Common::Point offset; - - if (!state) { - GFXERROR("Attempt to create view widget with NULL state!\n"); - return NULL; - } - - if (gfxop_get_cel_parameters(state, view, loop, cel, &width, &height, &offset)) { - GFXERROR("Attempt to retrieve cel parameters for (%d/%d/%d) failed (Maybe the values weren't checked beforehand?)\n", - view, cel, loop); - return NULL; - } - - widget = (gfxw_view_t *)_gfxw_new_widget(size, type); - - widget->widget_priority = priority; - widget->pos = pos; - widget->color.mask = ((priority < 0) ? 0 : GFX_MASK_PRIORITY) | ((control < 0) ? 0 : GFX_MASK_CONTROL); - widget->color.priority = priority; - widget->color.control = control; - widget->view = view; - widget->loop = loop; - widget->cel = cel; - widget->palette = palette; - - if (halign == ALIGN_CENTER) - widget->pos.x -= width >> 1; - else if (halign == ALIGN_RIGHT) - widget->pos.x -= width; - - if (valign == ALIGN_CENTER) - widget->pos.y -= height >> 1; - else if (valign == ALIGN_BOTTOM) - widget->pos.y -= height; - - widget->bounds = gfx_rect(widget->pos.x - offset.x, widget->pos.y - offset.y, width, height); - - widget->flags |= GFXW_FLAG_VISIBLE; - - return widget; -} - -int _gfxwop_view_draw(gfxw_widget_t *widget, Common::Point pos) { - gfxw_view_t *view = (gfxw_view_t *)widget; - DRAW_ASSERT(widget, GFXW_VIEW); - - GFX_ASSERT(gfxop_draw_cel(view->visual->gfx_state, view->view, view->loop, view->cel, - Common::Point(view->pos.x + pos.x, view->pos.y + pos.y), view->color, view->palette)); - - return 0; -} - -static int _gfxwop_static_view_draw(gfxw_widget_t *widget, Common::Point pos) { - gfxw_view_t *view = (gfxw_view_t *)widget; - DRAW_ASSERT(widget, GFXW_VIEW); - - GFX_ASSERT(gfxop_draw_cel_static(view->visual->gfx_state, view->view, view->loop, - view->cel, _move_point(view->bounds, pos), view->color, view->palette)); - - return 0; -} - -static int _w_gfxwop_view_print(gfxw_widget_t *widget, const char *name, int indentation) { - gfxw_view_t *view = (gfxw_view_t *)widget; - _gfxw_print_widget(widget, indentation); - - sciprintf(name); - sciprintf("(%d/%d/%d)@(%d,%d)[p:%d,c:%d]", view->view, view->loop, view->cel, view->pos.x, view->pos.y, - (view->color.mask & GFX_MASK_PRIORITY) ? view->color.priority : -1, - (view->color.mask & GFX_MASK_CONTROL) ? view->color.control : -1); - - return 0; -} - -static int _gfxwop_view_print(gfxw_widget_t *widget, int indentation) { - return _w_gfxwop_view_print(widget, "VIEW", indentation); -} - -static int _gfxwop_static_view_print(gfxw_widget_t *widget, int indentation) { - return _w_gfxwop_view_print(widget, "PICVIEW", indentation); -} - -void _gfxw_set_ops_VIEW(gfxw_widget_t *view, char stat) { - _gfxw_set_ops(GFXW(view), (stat) ? _gfxwop_static_view_draw : _gfxwop_view_draw, _gfxwop_basic_free, - _gfxwop_basic_tag, (stat) ? _gfxwop_static_view_print : _gfxwop_view_print, - _gfxwop_basic_compare_to, _gfxwop_basic_equals, _gfxwop_basic_superarea_of); -} - -gfxw_view_t *gfxw_new_view(gfx_state_t *state, Common::Point pos, int view_nr, int loop, int cel, int palette, int priority, int control, - gfx_alignment_t halign, gfx_alignment_t valign, int flags) { - gfxw_view_t *view; - - if (flags & GFXW_VIEW_FLAG_DONT_MODIFY_OFFSET) { - int foo; - Common::Point offset; - gfxop_get_cel_parameters(state, view_nr, loop, cel, &foo, &foo, &offset); - pos.x += offset.x; - pos.y += offset.y; - } - - view = _gfxw_new_simple_view(state, pos, view_nr, loop, cel, palette, priority, control, halign, valign, - sizeof(gfxw_view_t), (flags & GFXW_VIEW_FLAG_STATIC) ? GFXW_STATIC_VIEW : GFXW_VIEW); - - _gfxw_set_ops_VIEW(GFXW(view), (char)(flags & GFXW_VIEW_FLAG_STATIC)); - - return view; -} - -//*** Dynamic Views *** - -static int _gfxwop_dyn_view_draw(gfxw_widget_t *widget, Common::Point pos) { - gfxw_dyn_view_t *view = (gfxw_dyn_view_t *) widget; - DRAW_ASSERT(widget, GFXW_DYN_VIEW); - - GFX_ASSERT(gfxop_draw_cel(view->visual->gfx_state, view->view, view->loop, - view->cel, _move_point(view->draw_bounds, pos), view->color, view->palette)); - - /* - gfx_color_t red; - red.visual.r = 0xff; - red.visual.g = red.visual.b = 0; - red.mask = GFX_MASK_VISUAL; - GFX_ASSERT(gfxop_draw_rectangle(view->visual->gfx_state, - gfx_rect(view->bounds.x + pos.x, view->bounds.y + pos.y, view->bounds.xl - 1, view->bounds.yl - 1), red, 0, 0)); - */ - - return 0; - -} - -static int _gfxwop_draw_nop(gfxw_widget_t *widget, Common::Point pos) { - return 0; -} - -static int _gfxwop_pic_view_draw(gfxw_widget_t *widget, Common::Point pos) { - gfxw_dyn_view_t *view = (gfxw_dyn_view_t *) widget; - DRAW_ASSERT(widget, GFXW_PIC_VIEW); - - GFX_ASSERT(gfxop_set_clip_zone(view->visual->gfx_state, view->parent->zone)); - GFX_ASSERT(gfxop_draw_cel_static_clipped(view->visual->gfx_state, view->view, view->loop, - view->cel, _move_point(view->draw_bounds, pos), view->color, view->palette)); - - // Draw again on the back buffer - GFX_ASSERT(gfxop_draw_cel(view->visual->gfx_state, view->view, view->loop, view->cel, - _move_point(view->draw_bounds, pos), view->color, view->palette)); - - - widget->draw = _gfxwop_draw_nop; // No more drawing needs to be done - - return 0; -} - -static int _gfxwop_some_view_print(gfxw_widget_t *widget, int indentation, const char *type_string) { - gfxw_dyn_view_t *view = (gfxw_dyn_view_t *)widget; - - _gfxw_print_widget(widget, indentation); - - sciprintf(type_string); - sciprintf(" SORT=%d z=%d seq=%d (%d/%d/%d)@(%d,%d)[p:%d,c:%d]; sig[%04x@%p]", view->force_precedence, view->z, - view->sequence, view->view, view->loop, view->cel, view->pos.x, view->pos.y, - (view->color.mask & GFX_MASK_PRIORITY) ? view->color.priority : -1, - (view->color.mask & GFX_MASK_CONTROL) ? view->color.control : -1, view->signal, view->signalp); - - return 0; -} - -static int _gfxwop_dyn_view_print(gfxw_widget_t *widget, int indentation) { - return _gfxwop_some_view_print(widget, indentation, "DYNVIEW"); -} - -static int _gfxwop_pic_view_print(gfxw_widget_t *widget, int indentation) { - return _gfxwop_some_view_print(widget, indentation, "PICVIEW"); -} - -static int _gfxwop_dyn_view_equals(gfxw_widget_t *widget, gfxw_widget_t *other) { - gfxw_dyn_view_t *wview = (gfxw_dyn_view_t *)widget, *oview; - if (!GFXW_IS_DYN_VIEW(other)) - return 0; - - oview = (gfxw_dyn_view_t *)other; - - if (wview->pos.x != oview->pos.x || wview->pos.y != oview->pos.y || wview->z != oview->z) - return 0; - - if (wview->view != oview->view || wview->loop != oview->loop || wview->cel != oview->cel) - return 0; - - if (!_color_equals(wview->color, oview->color)) - return 0; - - if (wview->flags != oview->flags) - return 0; - - return 1; -} - -static int _gfxwop_dyn_view_compare_to(gfxw_widget_t *widget, gfxw_widget_t *other) { - int retval; - gfxw_dyn_view_t *wview = (gfxw_dyn_view_t *) widget, *oview; - if (!GFXW_IS_DYN_VIEW(other)) - return 1; - - oview = (gfxw_dyn_view_t *) other; - - retval = wview->force_precedence - oview->force_precedence; - if (retval) - return retval; - - retval = wview->pos.y - oview->pos.y; - if (retval) - return retval; - - retval = (wview->z - oview->z); - if (retval) - return retval; - - return -(wview->sequence - oview->sequence); -} - -void _gfxw_set_ops_DYNVIEW(gfxw_widget_t *widget) { - _gfxw_set_ops(GFXW(widget), _gfxwop_dyn_view_draw, _gfxwop_basic_free, _gfxwop_basic_tag, - _gfxwop_dyn_view_print, _gfxwop_dyn_view_compare_to, _gfxwop_dyn_view_equals, _gfxwop_basic_superarea_of); -} - -void _gfxw_set_ops_PICVIEW(gfxw_widget_t *widget) { - _gfxw_set_ops_DYNVIEW(widget); - widget->draw = _gfxwop_pic_view_draw; - widget->print = _gfxwop_pic_view_print; -} - -gfxw_dyn_view_t *gfxw_new_dyn_view(gfx_state_t *state, Common::Point pos, int z, int view, int loop, int cel, int palette, int priority, int control, - gfx_alignment_t halign, gfx_alignment_t valign, int sequence) { - gfxw_dyn_view_t *widget; - int width, height; - int xalignmod, yalignmod; - Common::Point offset; - - if (!state) { - GFXERROR("Attempt to create view widget with NULL state!\n"); - return NULL; - } - - if (gfxop_get_cel_parameters(state, view, loop, cel, &width, &height, &offset)) { - GFXERROR("Attempt to retrieve cel parameters for (%d/%d/%d) failed (Maybe the values weren't checked beforehand?)\n", - view, cel, loop); - return NULL; - } - - widget = (gfxw_dyn_view_t *)_gfxw_new_widget(sizeof(gfxw_dyn_view_t), GFXW_DYN_VIEW); - - widget->pos = pos; - widget->color.mask = ((priority < 0) ? 0 : GFX_MASK_PRIORITY) | ((control < 0) ? 0 : GFX_MASK_CONTROL); - widget->widget_priority = priority; - widget->color.priority = priority; - widget->color.control = control; - widget->color.alpha = 0; - widget->color.visual.global_index = 0; - widget->color.visual.r = 0; - widget->color.visual.g = 0; - widget->color.visual.b = 0; - widget->view = view; - widget->loop = loop; - widget->cel = cel; - widget->sequence = sequence; - widget->force_precedence = 0; - widget->palette = palette; - - if (halign == ALIGN_CENTER) - xalignmod = width >> 1; - else if (halign == ALIGN_RIGHT) - xalignmod = width; - else - xalignmod = 0; - - if (valign == ALIGN_CENTER) - yalignmod = height >> 1; - else if (valign == ALIGN_BOTTOM) - yalignmod = height; - else - yalignmod = 0; - - widget->z = z; - - widget->draw_bounds = gfx_rect(widget->pos.x - xalignmod, widget->pos.y - yalignmod - z, width, height); - widget->bounds = gfx_rect(widget->pos.x - offset.x - xalignmod, widget->pos.y - offset.y - yalignmod - z, width, height); - - widget->flags |= GFXW_FLAG_VISIBLE; - - _gfxw_set_ops_DYNVIEW(GFXW(widget)); - - widget->signalp = NULL; - widget->signal = 0; - - return widget; -} - -//*** Text *** - -static int _gfxwop_text_free(gfxw_widget_t *widget) { - gfxw_text_t *text = (gfxw_text_t *)widget; - free(text->text); - - return _gfxwop_basic_free(widget); -} - -static int _gfxwop_text_draw(gfxw_widget_t *widget, Common::Point pos) { - gfxw_text_t *text = (gfxw_text_t *)widget; - DRAW_ASSERT(widget, GFXW_TEXT); - - GFX_ASSERT(gfxop_draw_text(text->visual->gfx_state, text->text_handle, _move_rect(text->bounds, pos))); - - return 0; -} - -static int _gfxwop_text_alloc_and_draw(gfxw_widget_t *widget, Common::Point pos) { - gfxw_text_t *text = (gfxw_text_t *)widget; - DRAW_ASSERT(widget, GFXW_TEXT); - - text->text_handle = gfxop_new_text(widget->visual->gfx_state, text->font_nr, text->text, text->bounds.xl, - text->halign, text->valign, text->color1, text->color2, text->bgcolor, text->text_flags); - - text->draw = _gfxwop_text_draw; - - return _gfxwop_text_draw(widget, pos); -} - -static int _gfxwop_text_print(gfxw_widget_t *widget, int indentation) { - _gfxw_print_widget(widget, indentation); - sciprintf("TEXT:'%s'", ((gfxw_text_t *)widget)->text); - - return 0; -} - -static int _gfxwop_text_equals(gfxw_widget_t *widget, gfxw_widget_t *other) { - gfxw_text_t *wtext = (gfxw_text_t *)widget, *otext; - if (other->type != GFXW_TEXT) - return 0; - - otext = (gfxw_text_t *)other; - - if ((wtext->bounds.x != otext->bounds.x) || (wtext->bounds.y != otext->bounds.y)) - return 0; - - if (wtext->halign != otext->halign || wtext->valign != otext->valign) - return 0; - - if (wtext->text_flags != otext->text_flags) - return 0; - - if (wtext->font_nr != otext->font_nr) - return 0; - - /* if (!(_color_equals(wtext->color1, otext->color1) && _color_equals(wtext->color2, otext->color2) - && _color_equals(wtext->bgcolor, otext->bgcolor))) - return 0; */ - - return 1; -} - -static int _gfxwop_text_should_replace(gfxw_widget_t *widget, gfxw_widget_t *other) { - gfxw_text_t *wtext = (gfxw_text_t *)widget, *otext; - - if (other->type != GFXW_TEXT) - return 0; - - otext = (gfxw_text_t *)other; - - return strcmp(wtext->text, otext->text); -} - -static int _gfxwop_text_compare_to(gfxw_widget_t *widget, gfxw_widget_t *other) { - return 1; -} - -void _gfxw_set_ops_TEXT(gfxw_widget_t *widget) { - _gfxw_set_ops(GFXW(widget), _gfxwop_text_alloc_and_draw, _gfxwop_text_free, _gfxwop_basic_tag, - _gfxwop_text_print, _gfxwop_text_compare_to, _gfxwop_text_equals, - _gfxwop_basic_superarea_of); - widget->should_replace = _gfxwop_text_should_replace; -} - -gfxw_text_t *gfxw_new_text(gfx_state_t *state, rect_t area, int font, const char *text, gfx_alignment_t halign, - gfx_alignment_t valign, gfx_color_t color1, gfx_color_t color2, gfx_color_t bgcolor, int text_flags) { - gfxw_text_t *widget = (gfxw_text_t *)_gfxw_new_widget(sizeof(gfxw_text_t), GFXW_TEXT); - - widget->widget_priority = _gfxw_color_get_priority(color1); - widget->font_nr = font; - widget->text = (char *)sci_malloc(strlen(text) + 1); - widget->halign = halign; - widget->valign = valign; - widget->color1 = color1; - widget->color2 = color2; - widget->bgcolor = bgcolor; - widget->text_flags = text_flags; - widget->text_handle = NULL; - - strcpy(widget->text, text); - - gfxop_get_text_params(state, font, text, area.xl, &(widget->width), &(widget->height), text_flags, - &(widget->lines_nr), &(widget->lineheight), &(widget->lastline_width)); - - /* FIXME: Window is too big - area.x += _calc_needmove(halign, area.xl, widget->width); - area.y += _calc_needmove(valign, area.yl, widget->height); - */ - - if (halign == ALIGN_LEFT) - area.xl = widget->width; - if (valign == ALIGN_TOP) - area.yl = widget->height; - - widget->bounds = area; - - widget->flags |= GFXW_FLAG_VISIBLE; - - _gfxw_set_ops_TEXT(GFXW(widget)); - - return widget; -} - -void gfxw_text_info(gfx_state_t *state, gfxw_text_t *text, int *lines, int *lineheight, int *offset) { - if (lines) - *lines = text->lines_nr; - if (lineheight) - *lineheight = text->lineheight; - if (offset) - *offset = text->lastline_width; -} - -//-- Container types -- - -static int _gfxwop_container_add_dirty_rel(gfxw_container_t *cont, rect_t rect, int propagate) { - DDIRTY(stderr, "->container_add_dirty_rel(%d,%d,%d,%d, %d)\n", GFX_PRINT_RECT(rect), propagate); - return cont->add_dirty_abs(cont, _move_rect(rect, Common::Point(cont->zone.x, cont->zone.y)), propagate); -} - -static inline void _gfxw_set_container_ops(gfxw_container_t *container, gfxw_point_op *draw, gfxw_op *free, gfxw_op *tag, - gfxw_op_int *print, gfxw_bin_op *compare_to, gfxw_bin_op *equals, - gfxw_bin_op *superarea_of, gfxw_visual_op *set_visual, - gfxw_unary_container_op *free_tagged, gfxw_unary_container_op *free_contents, - gfxw_rect_op *add_dirty, gfxw_container_op *add) { - _gfxw_set_ops(GFXW(container), draw, free, tag, print, compare_to, equals, superarea_of); - - container->free_tagged = free_tagged; - container->free_contents = free_contents; - container->add_dirty_abs = add_dirty; - container->add_dirty_rel = _gfxwop_container_add_dirty_rel; - container->add = add; - container->set_visual = set_visual; -} - -static int _w_gfxwop_container_print_contents(const char *name, gfxw_widget_t *widget, int indentation) { - gfxw_widget_t *seeker = widget; - - indent(indentation); - - sciprintf("--%s:\n", name); - - while (seeker) { - seeker->print(seeker, indentation + 1); - sciprintf("\n"); - seeker = seeker->next; - } - - return 0; -} - -static int _w_gfxwop_container_print(gfxw_widget_t *widget, int indentation) { - gfx_dirty_rect_t *dirty; - gfxw_container_t *container = (gfxw_container_t *)widget; - if (!GFXW_IS_CONTAINER(widget)) { - GFXERROR("_w_gfxwop_container_print() called on type %d widget\n", widget->type); - return 1; - } - - sciprintf(" viszone=((%d,%d),(%dx%d))\n", container->zone.x, container->zone.y, - container->zone.xl, container->zone.yl); - - indent(indentation); - sciprintf("--dirty:\n"); - - dirty = container->dirty; - while (dirty) { - indent(indentation + 1); - sciprintf("dirty(%d,%d, (%dx%d))\n", dirty->rect.x, dirty->rect.y, dirty->rect.xl, dirty->rect.yl); - dirty = dirty->next; - } - - _w_gfxwop_container_print_contents("contents", container->contents, indentation); - - return 0; -} - -gfxw_container_t *_gfxw_new_container_widget(rect_t area, int size, gfxw_widget_type_t type) { - gfxw_container_t *widget = (gfxw_container_t *)_gfxw_new_widget(size, type); - - widget->bounds = widget->zone = area; - widget->contents = NULL; - widget->nextpp = &(widget->contents); - widget->dirty = NULL; - - widget->flags |= GFXW_FLAG_VISIBLE | GFXW_FLAG_CONTAINER; - - return widget; -} - -static void recursively_free_dirty_rects(gfx_dirty_rect_t *dirty) { - if (dirty) { - recursively_free_dirty_rects(dirty->next); - free(dirty); - } -} - -int ti = 0; - -static inline int _gfxw_dirty_rect_overlaps_normal_rect(rect_t port_zone, rect_t bounds, rect_t dirty) { - bounds.x += port_zone.x; - bounds.y += port_zone.y; - - return gfx_rects_overlap(bounds, dirty); -} - -static int _gfxwop_container_draw_contents(gfxw_widget_t *widget, gfxw_widget_t *contents) { - gfxw_container_t *container = (gfxw_container_t *)widget; - gfx_dirty_rect_t *dirty = container->dirty; - gfx_state_t *gfx_state = (widget->visual) ? widget->visual->gfx_state : ((gfxw_visual_t *) widget)->gfx_state; - int draw_ports; - rect_t nullzone = {0, 0, 0, 0}; - - if (!contents) - return 0; - - while (dirty) { - gfxw_widget_t *seeker = contents; - - while (seeker) { - if (_gfxw_dirty_rect_overlaps_normal_rect(GFXW_IS_CONTAINER(seeker) ? nullzone : container->zone, - // Containers have absolute coordinates, reflect this. - seeker->bounds, dirty->rect)) { - - if (GFXW_IS_CONTAINER(seeker)) {// Propagate dirty rectangles /upwards/ - DDIRTY(stderr, "container_draw_contents: propagate upwards (%d,%d,%d,%d ,0)\n", GFX_PRINT_RECT(dirty->rect)); - ((gfxw_container_t *)seeker)->add_dirty_abs((gfxw_container_t *)seeker, dirty->rect, 0); - } - - seeker->flags |= GFXW_FLAG_DIRTY; - } - - seeker = seeker->next; - } - - dirty = dirty->next; - } - - // The draw loop is executed twice: Once for normal data, and once for ports. - for (draw_ports = 0; draw_ports < 2; draw_ports++) { - dirty = container->dirty; - - while (dirty) { - gfxw_widget_t *seeker = contents; - while (seeker && (draw_ports || !GFXW_IS_PORT(seeker))) { - rect_t small_rect; - byte draw_noncontainers; - - memcpy(&small_rect, &(dirty->rect), sizeof(rect_t)); - draw_noncontainers = !_gfxop_clip(&small_rect, container->bounds); - - if (seeker->flags & GFXW_FLAG_DIRTY) { - - if (!GFXW_IS_CONTAINER(seeker) && draw_noncontainers) { - GFX_ASSERT(gfxop_set_clip_zone(gfx_state, small_rect)); - } - /* Clip zone must be reset after each element, because we might - ** descend into containers. - ** Doing this is relatively cheap, though. */ - if (draw_noncontainers || GFXW_IS_CONTAINER(seeker)) - seeker->draw(seeker, Common::Point(container->zone.x, container->zone.y)); - - if (!dirty->next) - seeker->flags &= ~GFXW_FLAG_DIRTY; - } - - seeker = seeker->next; - } - dirty = dirty->next; - } - } - // Remember that the dirty rects should be freed afterwards! - - return 0; -} - -static int _gfxwop_container_free(gfxw_widget_t *widget) { - gfxw_container_t *container = (gfxw_container_t *)widget; - gfxw_widget_t *seeker = container->contents; - - while (seeker) { - gfxw_widget_t *next = seeker->next; - seeker->widfree(seeker); - seeker = next; - } - - recursively_free_dirty_rects(container->dirty); - container->dirty = NULL; - - return _gfxwop_basic_free(widget); -} - -static int _gfxwop_container_tag(gfxw_widget_t *widget) { - gfxw_container_t *container = (gfxw_container_t *) widget; - gfxw_widget_t *seeker = container->contents; - - while (seeker) { - seeker->tag(seeker); - seeker = seeker->next; - } - - return 0; -} - -static int _w_gfxwop_container_set_visual_contents(gfxw_widget_t *contents, gfxw_visual_t *visual) { - while (contents) { - contents->set_visual(contents, visual); - contents = contents->next; - } - return 0; -} - -static int _gfxwop_container_set_visual(gfxw_widget_t *widget, gfxw_visual_t *visual) { - gfxw_container_t *container = (gfxw_container_t *) widget; - - container->visual = visual; - if (widget->parent) { - if (!(GFXW_IS_LIST(widget) && !GFXWC(widget)->contents)) { - DDIRTY(stderr, "set_visual::DOWNWARDS abs(%d,%d,%d,%d, 1)\n", GFX_PRINT_RECT(widget->bounds)); - widget->parent->add_dirty_abs(widget->parent, widget->bounds, 1); - } - } - - return _w_gfxwop_container_set_visual_contents(container->contents, visual); -} - -static int _gfxwop_container_free_tagged(gfxw_container_t *container) { - gfxw_widget_t *seekerp = (container->contents); - - while (seekerp) { - gfxw_widget_t *redshirt = seekerp; - - if (redshirt->flags & GFXW_FLAG_TAGGED) { - seekerp = (redshirt->next); - redshirt->widfree(redshirt); - } else - seekerp = (seekerp)->next; - } - - return 0; -} - -static int _gfxwop_container_free_contents(gfxw_container_t *container) { - gfxw_widget_t *seeker = container->contents; - - while (seeker) { - gfxw_widget_t *next = seeker->next; - seeker->widfree(seeker); - seeker = next; - } - return 0; -} - -static void _gfxw_dirtify_container(gfxw_container_t *container, gfxw_widget_t *widget) { - if (GFXW_IS_CONTAINER(widget)) - container->add_dirty_abs(GFXWC(container), widget->bounds, 1); - else - container->add_dirty_rel(GFXWC(container), widget->bounds, 1); -} - -static int _parentize_widget(gfxw_container_t *container, gfxw_widget_t *widget) { - if (widget->parent) { - GFXERROR("_gfxwop_container_add(): Attempt to give second parent node to widget!\nWidget:"); - widget->print(GFXW(widget), 3); - sciprintf("\nContainer:"); - container->print(GFXW(container), 3); - - return 1; - } - - widget->parent = GFXWC(container); - - if (GFXW_IS_VISUAL(container)) - widget->set_visual(widget, (gfxw_visual_t *) container); - else if (container->visual) - widget->set_visual(widget, container->visual); - - return 0; -} - -static int _gfxw_container_id_equals(gfxw_container_t *container, gfxw_widget_t *widget) { - gfxw_widget_t **seekerp = &(container->contents); - - if (GFXW_IS_PORT(widget)) - return 0; - - if (widget->ID == GFXW_NO_ID) - return 0; - - while (*seekerp && ((*seekerp)->ID != widget->ID || (*seekerp)->subID != widget->subID)) - seekerp = &((*seekerp)->next); - - if (!*seekerp) - return 0; - - if ((*seekerp)->equals(*seekerp, widget) && !(*seekerp)->should_replace(*seekerp, widget)) { - widget->widfree(widget); - (*seekerp)->flags &= ~GFXW_FLAG_TAGGED; - return 1; - } else { - if (!(widget->flags & GFXW_FLAG_MULTI_ID)) - (*seekerp)->widfree(*seekerp); - return 0; - } -} - -static int _gfxwop_container_add_dirty(gfxw_container_t *container, rect_t dirty, int propagate) { -#if 0 - // This code has been disabled because containers may contain sub-containers with - // bounds greater than their own. - if (_gfxop_clip(&dirty, container->bounds)) - return 0; -#endif - - DDIRTY(stderr, "Effectively adding dirty %d,%d,%d,%d %d to ID %d\n", GFX_PRINT_RECT(dirty), propagate, container->ID); - container->dirty = gfxdr_add_dirty(container->dirty, dirty, GFXW_DIRTY_STRATEGY); - return 0; -} - -static int _gfxwop_container_add(gfxw_container_t *container, gfxw_widget_t *widget) { - if (_gfxw_container_id_equals(container, widget)) - return 0; - - if (_parentize_widget(container, widget)) - return 1; - - if (!(GFXW_IS_LIST(widget) && (!GFXWC(widget)->contents))) { // Don't dirtify self on empty lists - DDIRTY(stderr, "container_add: dirtify DOWNWARDS (%d,%d,%d,%d, 1)\n", GFX_PRINT_RECT(widget->bounds)); - _gfxw_dirtify_container(container, widget); - } - - *(container->nextpp) = widget; - container->nextpp = &(widget->next); - - return 0; -} - -//*** Lists and sorted lists *** - -static int _gfxwop_list_draw(gfxw_widget_t *list, Common::Point pos) { - DRAW_ASSERT(list, GFXW_LIST); - - _gfxwop_container_draw_contents(list, ((gfxw_list_t *)list)->contents); - recursively_free_dirty_rects(GFXWC(list)->dirty); - GFXWC(list)->dirty = NULL; - list->flags &= ~GFXW_FLAG_DIRTY; - - return 0; -} - -static int _gfxwop_sorted_list_draw(gfxw_widget_t *list, Common::Point pos) { - DRAW_ASSERT(list, GFXW_SORTED_LIST); - - _gfxwop_container_draw_contents(list, ((gfxw_list_t *)list)->contents); - recursively_free_dirty_rects(GFXWC(list)->dirty); - GFXWC(list)->dirty = NULL; - - return 0; -} - -static inline int _w_gfxwop_list_print(gfxw_widget_t *list, const char *name, int indentation) { - _gfxw_print_widget(list, indentation); - sciprintf(name); - - return _w_gfxwop_container_print(list, indentation); -} - -static int _gfxwop_list_print(gfxw_widget_t *list, int indentation) { - return _w_gfxwop_list_print(list, "LIST", indentation); -} - -static int _gfxwop_sorted_list_print(gfxw_widget_t *list, int indentation) { - return _w_gfxwop_list_print(list, "SORTED_LIST", indentation); -} - -#if 0 -struct gfxw_widget_list { - gfxw_widget_t *widget; - struct gfxw_widget_list *next; -}; - -static struct gfxw_widtet_list *_gfxw_make_widget_list_recursive(gfxw_widget_t *widget) { - gfxw_widget_list *node; - - if (!widget) - return NULL; - - node = sci_malloc(sizeof(struct gfxw_widget_list)); - node->widget = widget; - node->next = _gfxw_make_widget_list_recursive(widget->next); - - return node; -} - -static struct gfxw_widget_list *_gfxw_make_widget_list(gfxw_container_t *container) { - return _gfxw_make_widget_list_recursive(container->contents); -} -#endif - -static int _gfxwop_list_equals(gfxw_widget_t *widget, gfxw_widget_t *other) { - // Requires identical order of list elements. - gfxw_list_t *wlist, *olist; - - if (widget->type != other->type) - return 0; - - if (!GFXW_IS_LIST(widget)) { - GFXWARN("_gfxwop_list_equals(): Method called on non-list!\n"); - widget->print(widget, 0); - sciprintf("\n"); - return 0; - } - - wlist = (gfxw_list_t *)widget; - olist = (gfxw_list_t *)other; - - if (memcmp(&(wlist->bounds), &(olist->bounds), sizeof(rect_t))) - return 0; - - widget = wlist->contents; - other = olist->contents; - - while (widget && other) { - if (!(widget->equals(widget, other) && !widget->should_replace(widget, other))) - return 0; - - widget = widget->next; - other = other->next; - } - - return (!widget && !other); // True if both are finished now -} - -static int _gfxwop_list_add_dirty(gfxw_container_t *container, rect_t dirty, int propagate) { - // Lists add dirty boxes to both themselves and their parenting port/visual - - container->flags |= GFXW_FLAG_DIRTY; - - DDIRTY(stderr, "list_add_dirty %d,%d,%d,%d %d\n", GFX_PRINT_RECT(dirty), propagate); - if (propagate) - if (container->parent) { - DDIRTY(stderr, "->PROPAGATING\n"); - container->parent->add_dirty_abs(container->parent, dirty, 1); - } - - return _gfxwop_container_add_dirty(container, dirty, propagate); -} - -int _gfxwop_ordered_add(gfxw_container_t *container, gfxw_widget_t *widget, int compare_all) { - // O(n) - gfxw_widget_t **seekerp = &(container->contents); - - if (widget->next) { - GFXERROR("_gfxwop_sorted_list_add(): Attempt to add widget to two lists!\nWidget:"); - widget->print(GFXW(widget), 3); - sciprintf("\nList:"); - container->print(GFXW(container), 3); - BREAKPOINT(); - - return 1; - } - - if (_gfxw_container_id_equals(container, widget)) - return 0; - - while (*seekerp && (compare_all || (widget->compare_to(widget, *seekerp) >= 0))) { - - if (widget->equals(GFXW(widget), GFXW(*seekerp))) { - if (compare_all) { - if ((*seekerp)->visual) - (*seekerp)->widfree(GFXW(*seekerp)); // If it's a fresh widget - else - gfxw_annihilate(GFXW(*seekerp)); - - return _gfxwop_ordered_add(container, widget, compare_all); // We might have destroyed the container's contents - } else { - widget->next = (*seekerp)->next; - (*seekerp)->widfree(GFXW(*seekerp)); - *seekerp = widget; - return (_parentize_widget(container, widget)); - } - } - - if (*seekerp) - seekerp = &((*seekerp)->next); - } - - widget->next = *seekerp; - *seekerp = widget; - - return _parentize_widget(container, widget); -} - -static int _gfxwop_sorted_list_add(gfxw_container_t *container, gfxw_widget_t *widget) { - // O(n) - return _gfxwop_ordered_add(container, widget, 0); -} - -void _gfxw_set_ops_LIST(gfxw_container_t *list, char sorted) { - _gfxw_set_container_ops((gfxw_container_t *)list, sorted ? _gfxwop_sorted_list_draw : _gfxwop_list_draw, - _gfxwop_container_free, _gfxwop_container_tag, - sorted ? _gfxwop_sorted_list_print : _gfxwop_list_print, - _gfxwop_basic_compare_to, sorted ? _gfxwop_basic_equals : _gfxwop_list_equals, - _gfxwop_basic_superarea_of, _gfxwop_container_set_visual, - _gfxwop_container_free_tagged, _gfxwop_container_free_contents, - _gfxwop_list_add_dirty, sorted ? _gfxwop_sorted_list_add : _gfxwop_container_add); -} - -gfxw_list_t *gfxw_new_list(rect_t area, int sorted) { - gfxw_list_t *list = (gfxw_list_t *) _gfxw_new_container_widget(area, sizeof(gfxw_list_t), - sorted ? GFXW_SORTED_LIST : GFXW_LIST); - - _gfxw_set_ops_LIST(GFXWC(list), (char)sorted); - - return list; -} - -//*** Visuals *** - -static int _gfxwop_visual_draw(gfxw_widget_t *widget, Common::Point pos) { - gfxw_visual_t *visual = (gfxw_visual_t *) widget; - gfx_dirty_rect_t *dirty = visual->dirty; - DRAW_ASSERT(widget, GFXW_VISUAL); - - while (dirty) { - int err = gfxop_clear_box(visual->gfx_state, dirty->rect); - - if (err) { - GFXERROR("Error while clearing dirty rect (%d,%d,(%dx%d))\n", dirty->rect.x, - dirty->rect.y, dirty->rect.xl, dirty->rect.yl); - if (err == GFX_FATAL) - return err; - } - - dirty = dirty->next; - } - - _gfxwop_container_draw_contents(widget, visual->contents); - - recursively_free_dirty_rects(visual->dirty); - visual->dirty = NULL; - widget->flags &= ~GFXW_FLAG_DIRTY; - - return 0; -} - -static int _gfxwop_visual_free(gfxw_widget_t *widget) { - gfxw_visual_t *visual = (gfxw_visual_t *) widget; - gfxw_port_t **portrefs; - int retval; - - if (!GFXW_IS_VISUAL(visual)) { - GFXERROR("_gfxwop_visual_free() called on non-visual!Widget was: "); - widget->print(widget, 3); - return 1; - } - - portrefs = visual->port_refs; - - retval = _gfxwop_container_free(widget); - - free(portrefs); - - return 0; -} - -static int _gfxwop_visual_print(gfxw_widget_t *widget, int indentation) { - int i; - int comma = 0; - gfxw_visual_t *visual = (gfxw_visual_t *) widget; - - if (!GFXW_IS_VISUAL(visual)) { - GFXERROR("_gfxwop_visual_free() called on non-visual!Widget was: "); - widget->print(widget, 3); - return 1; - } - - _gfxw_print_widget(widget, indentation); - sciprintf("VISUAL; ports={"); - for (i = 0; i < visual->port_refs_nr; i++) - if (visual->port_refs[i]) { - if (comma) - sciprintf(","); - else - comma = 1; - - sciprintf("%d", i); - } - sciprintf("}\n"); - - return _w_gfxwop_container_print(widget, indentation); -} - -static int _gfxwop_visual_set_visual(gfxw_widget_t *self, gfxw_visual_t *visual) { - if (self != GFXW(visual)) { - GFXWARN("Attempt to set a visual's parent visual to something else!\n"); - } else { - GFXWARN("Attempt to set a visual's parent visual!\n"); - } - - return 1; -} - -void _gfxw_set_ops_VISUAL(gfxw_container_t *visual) { - _gfxw_set_container_ops((gfxw_container_t *)visual, _gfxwop_visual_draw, _gfxwop_visual_free, - _gfxwop_container_tag, _gfxwop_visual_print, _gfxwop_basic_compare_to, - _gfxwop_basic_equals, _gfxwop_basic_superarea_of, _gfxwop_visual_set_visual, - _gfxwop_container_free_tagged, _gfxwop_container_free_contents, - _gfxwop_container_add_dirty, _gfxwop_container_add); -} - -gfxw_visual_t *gfxw_new_visual(gfx_state_t *state, int font) { - gfxw_visual_t *visual = (gfxw_visual_t *) _gfxw_new_container_widget(gfx_rect(0, 0, 320, 200), sizeof(gfxw_visual_t), GFXW_VISUAL); - - visual->font_nr = font; - visual->gfx_state = state; - - visual->port_refs_nr = 16; - visual->port_refs = (gfxw_port_t **)sci_calloc(sizeof(gfxw_port_t), visual->port_refs_nr); - - _gfxw_set_ops_VISUAL(GFXWC(visual)); - - return visual; -} - -static int _visual_find_free_ID(gfxw_visual_t *visual) { - int id = 0; - int newports = 16; - - while (visual->port_refs[id] && id < visual->port_refs_nr) - id++; - - if (id == visual->port_refs_nr) { // Out of ports? - visual->port_refs_nr += newports; - visual->port_refs = (gfxw_port_t**)sci_realloc(visual->port_refs, visual->port_refs_nr); - memset(visual->port_refs + id, 0, newports * sizeof(gfxw_port_t *)); // Clear new port refs - } - - return id; -} - -static int _gfxwop_add_dirty_rects(gfxw_container_t *dest, gfx_dirty_rect_t *src) { - DDIRTY(stderr, "Adding multiple dirty to #%d\n", dest->ID); - if (src) { - dest->dirty = gfxdr_add_dirty(dest->dirty, src->rect, GFXW_DIRTY_STRATEGY); - _gfxwop_add_dirty_rects(dest, src->next); - } - - return 0; -} - -//*** Ports *** - -static int _gfxwop_port_draw(gfxw_widget_t *widget, Common::Point pos) { - gfxw_port_t *port = (gfxw_port_t *) widget; - DRAW_ASSERT(widget, GFXW_PORT); - - if (port->decorations) { - DDIRTY(stderr, "Getting/applying deco dirty (multi)\n"); - _gfxwop_add_dirty_rects(GFXWC(port->decorations), port->dirty); - if (port->decorations->draw(GFXW(port->decorations), gfxw_point_zero)) { - port->decorations->dirty = NULL; - return 1; - } - port->decorations->dirty = NULL; - } - - _gfxwop_container_draw_contents(widget, port->contents); - - recursively_free_dirty_rects(port->dirty); - port->dirty = NULL; - widget->flags &= ~GFXW_FLAG_DIRTY; - - return 0; -} - -static int _gfxwop_port_free(gfxw_widget_t *widget) { - gfxw_port_t *port = (gfxw_port_t *) widget; - - if (port->visual) { - gfxw_visual_t *visual = port->visual; - int ID = port->ID; - - if (ID < 0 || ID >= visual->port_refs_nr) { - GFXWARN("Attempt to free port #%d; allowed: [0..%d]!\n", ID, visual->port_refs_nr); - return GFX_ERROR; - } - - if (visual->port_refs[ID] != port) { - GFXWARN("While freeing port %d: Port is at %p, but port list indicates %p", ID, (void *)port, (void *)visual->port_refs[ID]); - } else - visual->port_refs[ID] = NULL; - - } - - if (port->decorations) - port->decorations->widfree(GFXW(port->decorations)); - - return _gfxwop_container_free(widget); -} - -static int _gfxwop_port_print(gfxw_widget_t *widget, int indentation) { - gfxw_port_t *port = (gfxw_port_t *)widget; - - _gfxw_print_widget(widget, indentation); - sciprintf("PORT"); - sciprintf(" font=%d drawpos=(%d,%d)", port->font_nr, port->draw_pos.x, port->draw_pos.y); - if (port->gray_text) - sciprintf(" (gray)"); - _w_gfxwop_container_print(GFXW(port), indentation); - - return _w_gfxwop_container_print_contents("decorations", GFXW(port->decorations), indentation); -} - -static int _gfxwop_port_superarea_of(gfxw_widget_t *self, gfxw_widget_t *other) { - gfxw_port_t *port = (gfxw_port_t *) self; - - if (!port->port_bg) - return _gfxwop_basic_superarea_of(self, other); - - return port->port_bg->superarea_of(port->port_bg, other); -} - -static int _gfxwop_port_set_visual(gfxw_widget_t *widget, gfxw_visual_t *visual) { - gfxw_list_t *decorations = ((gfxw_port_t *) widget)->decorations; - widget->visual = visual; - - if (decorations) - if (decorations->set_visual(GFXW(decorations), visual)) { - GFXWARN("Setting the visual for decorations failed for port "); - widget->print(widget, 1); - return 1; - } - - return _gfxwop_container_set_visual(widget, visual); -} - -static int _gfxwop_port_add_dirty(gfxw_container_t *widget, rect_t dirty, int propagate) { - gfxw_port_t *self = (gfxw_port_t *) widget; - - self->flags |= GFXW_FLAG_DIRTY; - - _gfxwop_container_add_dirty(widget, dirty, propagate); - - DDIRTY(stderr, "Added dirty to ID %d\n", widget->ID); - DDIRTY(stderr, "dirty= (%d,%d,%d,%d) bounds (%d,%d,%d,%d)\n", dirty.x, dirty.x, dirty.xl, dirty.yl, - widget->bounds.x, widget->bounds.y, widget->bounds.xl, widget->bounds.yl); -#if 0 - // FIXME: This is a worthwhile optimization - if (self->port_bg) { - gfxw_widget_t foo; - - foo.bounds = dirty; // Yeah, sub-elegant, I know - foo.bounds.x -= self->zone.x; - foo.bounds.y -= self->zone.y; - if (self->port_bg->superarea_of(self->port_bg, &foo)) { - gfxw_container_t *parent = self->parent; - while (parent) { - fprintf(stderr, "Dirtifying parent id %d\n", parent->ID); - parent->flags |= GFXW_FLAG_DIRTY; - parent = parent->parent; - } - return 0; - } - } // else propagate to the parent, since we're not 'catching' the dirty rect -#endif - - if (propagate) - if (self->parent) { - DDIRTY(stderr, "PROPAGATE\n"); - return self->parent->add_dirty_abs(self->parent, dirty, 1); - } - - return 0; -} - -static int _gfxwop_port_add(gfxw_container_t *container, gfxw_widget_t *widget) { - // O(n) - return _gfxwop_ordered_add(container, widget, 1); -} - -void _gfxw_set_ops_PORT(gfxw_container_t *widget) { - _gfxw_set_container_ops((gfxw_container_t *)widget, _gfxwop_port_draw, _gfxwop_port_free, _gfxwop_container_tag, - _gfxwop_port_print, _gfxwop_basic_compare_to, _gfxwop_basic_equals, _gfxwop_port_superarea_of, - _gfxwop_port_set_visual, _gfxwop_container_free_tagged, _gfxwop_container_free_contents, - _gfxwop_port_add_dirty, _gfxwop_port_add); -} - -gfxw_port_t *gfxw_new_port(gfxw_visual_t *visual, gfxw_port_t *predecessor, rect_t area, gfx_color_t fgcolor, gfx_color_t bgcolor) { - gfxw_port_t *widget = (gfxw_port_t *)_gfxw_new_container_widget(area, sizeof(gfxw_port_t), GFXW_PORT); - - VERIFY_WIDGET(visual); - - widget->port_bg = NULL; - widget->parent = NULL; - widget->decorations = NULL; - widget->title_text = NULL; - widget->draw_pos = Common::Point(0, 0); - widget->gray_text = 0; - widget->color = fgcolor; - widget->bgcolor = bgcolor; - widget->font_nr = visual->font_nr; - widget->ID = _visual_find_free_ID(visual); - widget->chrono_port = 0; - visual->port_refs[widget->ID] = widget; - - _gfxw_set_ops_PORT(GFXWC(widget)); - - return widget; -} - -void gfxw_port_auto_restore_background(gfxw_visual_t *visual, gfxw_port_t *window, rect_t auto_rect) { - window->port_flags |= WINDOW_FLAG_AUTO_RESTORE; - window->restore_snap = gfxw_make_snapshot(visual, auto_rect); -} - -gfxw_port_t *gfxw_remove_port(gfxw_visual_t *visual, gfxw_port_t *port) { - gfxw_port_t *parent; - VERIFY_WIDGET(visual); - VERIFY_WIDGET(port); - - if (!visual->contents) { - GFXWARN("Attempt to remove port from empty visual\n"); - return NULL; - } - - parent = (gfxw_port_t *)port->parent; - if (port->port_flags & WINDOW_FLAG_AUTO_RESTORE) - gfxw_restore_snapshot(visual, port->restore_snap); - - if (port->widfree(GFXW(port))) - return parent; - - while (parent && !GFXW_IS_PORT(parent)) - parent = (gfxw_port_t *)parent->parent; // Ascend through ancestors - - return parent; -} - -gfxw_port_t *gfxw_find_port(gfxw_visual_t *visual, int ID) { - if (ID < 0 || ID >= visual->port_refs_nr) - return NULL; - - return visual->port_refs[ID]; -} - -gfxw_port_t *gfxw_find_default_port(gfxw_visual_t *visual) { - int id = visual->port_refs_nr; - - while (id--) { - gfxw_port_t *port = visual->port_refs[id]; - - if (port) - return port; - } - - return NULL; -} - -// - other functions - - -gfxw_widget_t *gfxw_set_id(gfxw_widget_t *widget, int ID, int subID) { - if (widget) { - widget->ID = ID; - widget->subID = subID; - } - - return widget; -} - -gfxw_dyn_view_t *gfxw_dyn_view_set_params(gfxw_dyn_view_t *widget, int under_bits, void *under_bitsp, int signal, void *signalp) { - if (!widget) - return NULL; - - widget->under_bits = under_bits; - widget->under_bitsp = under_bitsp; - widget->signal = signal; - widget->signalp = signalp; - - return widget; -} - -gfxw_widget_t *gfxw_remove_id(gfxw_container_t *container, int ID, int subID) { - gfxw_widget_t **wp = &(container->contents); - - while (*wp) { - if ((*wp)->ID == ID && (subID == GFXW_NO_ID || (*wp)->subID == subID)) { - gfxw_widget_t *widget = *wp; - - *wp = (*wp)->next; - widget->next = NULL; - widget->parent = NULL; - widget->visual = NULL; - - return widget; - } - - wp = &((*wp)->next); - } - - return NULL; -} - -gfxw_widget_t *gfxw_hide_widget(gfxw_widget_t *widget) { - if (widget->flags & GFXW_FLAG_VISIBLE) { - widget->flags &= ~GFXW_FLAG_VISIBLE; - - if (widget->parent) - widget->parent->add_dirty_rel(widget->parent, widget->bounds, 1); - } - - return widget; -} - -gfxw_widget_t *gfxw_show_widget(gfxw_widget_t *widget) { - if (!(widget->flags & GFXW_FLAG_VISIBLE)) { - widget->flags |= GFXW_FLAG_VISIBLE; - - if (widget->parent) - widget->parent->add_dirty_rel(widget->parent, widget->bounds, 1); - } - - return widget; -} - -gfxw_snapshot_t *gfxw_make_snapshot(gfxw_visual_t *visual, rect_t area) { - gfxw_snapshot_t *retval = (gfxw_snapshot_t*)sci_malloc(sizeof(gfxw_snapshot_t)); - - retval->serial = widget_serial_number_counter++; - - retval->area = area; - - // Work around subset semantics in gfx_rect_subset. - // This fixes the help icon in LSL5. */ - if (retval->area.xl == 320) retval->area.xl = 321; - - return retval; -} - -int gfxw_widget_matches_snapshot(gfxw_snapshot_t *snapshot, gfxw_widget_t *widget) { - int free_below = (snapshot->serial < widget_serial_number_counter) ? 0 : widget_serial_number_counter; - int free_above_eq = snapshot->serial; - rect_t bounds = widget->bounds; - - if (!GFXW_IS_CONTAINER(widget) && widget->parent) { - bounds.x += widget->parent->bounds.x; - bounds.y += widget->parent->bounds.y; - } - - return ((widget->serial >= free_above_eq || widget->serial < free_below) && gfx_rect_subset(bounds, snapshot->area)); -} - -#define MAGIC_FREE_NUMBER -42 - -void _gfxw_free_contents_appropriately(gfxw_container_t *container, gfxw_snapshot_t *snapshot, int priority) { - gfxw_widget_t *widget = container->contents; - - while (widget) { - gfxw_widget_t *next = widget->next; - - if (gfxw_widget_matches_snapshot(snapshot, widget) && !(widget->flags & GFXW_FLAG_IMMUNE_TO_SNAPSHOTS) - && (priority == MAGIC_FREE_NUMBER || priority <= widget->widget_priority || widget->widget_priority == -1)) { - widget->widfree(widget); - } else { - if (GFXW_IS_CONTAINER(widget)) - _gfxw_free_contents_appropriately(GFXWC(widget), snapshot, priority); - } - - widget = next; - } -} - -gfxw_snapshot_t *gfxw_restore_snapshot(gfxw_visual_t *visual, gfxw_snapshot_t *snapshot) { - _gfxw_free_contents_appropriately(GFXWC(visual), snapshot, MAGIC_FREE_NUMBER); - - return snapshot; -} - -void gfxw_annihilate(gfxw_widget_t *widget) { - gfxw_visual_t *visual = widget->visual; - int widget_priority = 0; - int free_overdrawn = 0; - - gfxw_snapshot_t snapshot; - if (!GFXW_IS_CONTAINER(widget) && widget->parent && visual && (widget->flags & GFXW_FLAG_VISIBLE)) { - snapshot.serial = 0; - snapshot.area = widget->bounds; - snapshot.area.x += widget->parent->zone.x; - snapshot.area.y += widget->parent->zone.y; - free_overdrawn = 1; - widget_priority = widget->widget_priority; - } - - widget->widfree(GFXW(widget)); - - if (free_overdrawn) - _gfxw_free_contents_appropriately(GFXWC(visual), &snapshot, widget_priority); -} - -gfxw_dyn_view_t *gfxw_picviewize_dynview(gfxw_dyn_view_t *dynview) { - dynview->type = GFXW_PIC_VIEW; - dynview->flags |= GFXW_FLAG_DIRTY; - - _gfxw_set_ops_PICVIEW(GFXW(dynview)); - - if (dynview->parent) - _gfxw_dirtify_container(dynview->parent, GFXW(dynview)); - - return dynview; -} - -// Chrono-Ports (tm) - -gfxw_port_t * gfxw_get_chrono_port(gfxw_visual_t *visual, gfxw_list_t **temp_widgets_list, int flags) { - gfxw_port_t *result = NULL; - gfx_color_t transparent = {{0, 0, 0, 0}, 0, 0, 0, 0}; - int id = 0; - - if (!(flags & GFXW_CHRONO_NON_TOPMOST)) { - result = gfxw_find_default_port(visual); - } else { - id = visual->port_refs_nr; - while (id >= 0 && (!visual->port_refs[id] || !visual->port_refs[id]->chrono_port)) - id--; - - if (id >= 0) - result = visual->port_refs[id]; - } - - if (!result || !result->chrono_port) { - if (flags & GFXW_CHRONO_NO_CREATE) - return NULL; - result = gfxw_new_port(visual, NULL, gfx_rect(0, 0, 320, 200), transparent, transparent); - *temp_widgets_list = gfxw_new_list(gfx_rect(0, 0, 320, 200), 1); - result->add(GFXWC(result), GFXW(*temp_widgets_list)); - result->chrono_port = 1; - if (temp_widgets_list) - *temp_widgets_list = GFXWC(result->contents); - return result; - }; - - if (temp_widgets_list) - *temp_widgets_list = GFXWC(result->contents); - - return result; -} - -static int gfxw_check_chrono_overlaps(gfxw_port_t *chrono, gfxw_widget_t *widget) { - gfxw_widget_t *seeker = GFXWC(chrono->contents)->contents; - - while (seeker) { - if (gfx_rect_equals(seeker->bounds, widget->bounds)) { - gfxw_annihilate(GFXW(seeker)); - return 1; - } - - seeker = seeker->next; - } - - return 0; -} - -void gfxw_add_to_chrono(gfxw_visual_t *visual, gfxw_widget_t *widget) { - gfxw_list_t *tw; - gfxw_port_t *chrono = gfxw_get_chrono_port(visual, &tw, 0); - - gfxw_check_chrono_overlaps(chrono, widget); - chrono->add(GFXWC(chrono), widget); -} - -static gfxw_widget_t *gfxw_widget_intersects_chrono(gfxw_list_t *tw, gfxw_widget_t *widget) { - gfxw_widget_t *seeker; - - assert(tw->type == GFXW_SORTED_LIST); - - seeker = tw->contents; - while (seeker) { - Common::Point origin; - rect_t bounds = widget->bounds; - - bounds = widget->bounds; - origin.x = seeker->parent->zone.x; - origin.y = seeker->parent->zone.y; - gfx_rect_translate(bounds, origin); - - if (gfx_rects_overlap(bounds, seeker->bounds)) - return seeker; - - seeker = seeker->next; - } - - return 0; -} - -void gfxw_widget_reparent_chrono(gfxw_visual_t *visual, gfxw_widget_t *view, gfxw_list_t *target) { - gfxw_list_t *tw; - gfxw_port_t *chrono; - gfxw_widget_t *intersector; - - chrono = gfxw_get_chrono_port(visual, &tw, GFXW_CHRONO_NO_CREATE); - if (chrono == NULL) - return; - - intersector = gfxw_widget_intersects_chrono(tw, view); - if (intersector) { - Common::Point origin = Common::Point(intersector->parent->zone.x, intersector->parent->zone.y); - - gfxw_remove_widget_from_container(GFXWC(chrono), GFXW(tw)); - gfxw_remove_widget_from_container(GFXWC(chrono->parent), GFXW(chrono)); - gfxw_annihilate(GFXW(chrono)); - - gfx_rect_translate(tw->zone, origin); - target->add(GFXWC(target), GFXW(tw)); - } -} - -void gfxw_widget_kill_chrono(gfxw_visual_t *visual, int window) { - int i; - - for (i = window; i < visual->port_refs_nr ; i++) { - if (visual->port_refs[i] && visual->port_refs[i]->chrono_port) - gfxw_annihilate(GFXW(visual->port_refs[i])); - } -} - -} // End of namespace Sci diff --git a/engines/sci/include/sci_widgets.h b/engines/sci/include/sci_widgets.h deleted file mode 100644 index ea7199dcc1..0000000000 --- a/engines/sci/include/sci_widgets.h +++ /dev/null @@ -1,205 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/* SCI-specific widget handling */ - -#ifndef SCI_INCLUDE_SCI_WIDGETS_H -#define SCI_INCLUDE_SCI_WIDGETS_H - -#include "sci/include/engine.h" - -namespace Sci { - -struct menu_t; - -/* The following flags are applicable to windows in SCI0: */ -#define WINDOW_FLAG_TRANSPARENT 0x01 - - -#define WINDOW_FLAG_NOFRAME 0x02 -/* No frame is drawn around the window onto wm_view */ - -#define WINDOW_FLAG_TITLE 0x04 -/* Add titlebar to window (10 pixels high, framed, text is centered and written -** in white on dark gray -*/ - -#define WINDOW_FLAG_DONTDRAW 0x80 -/* Don't draw anything */ - -#define WINDOW_FLAG_NO_DROP_SHADOW 0x1000000 - - -/* Used in kgraphics to flag text surrounded by a dithered frame */ -#define CONTROL_STATE_DITHER_FRAMED 0x1000 - -/* Used by the interpreter to flag buttons that are grayed out */ -#define CONTROL_STATE_GRAY 0x0004 -/* Used by the interpreter to flag some widgets to determine whether they should be surrounded by a frame */ -#define CONTROL_STATE_FRAMED 0x0008 -/* Used by the interpreter to flag buttons that are enabled */ -#define CONTROL_STATE_ENABLED 0x0001 - -void sciw_set_status_bar(EngineState *s, gfxw_port_t *status_bar, char *text, int fgcolor, int bgcolor); -/* Sets the contents of a port used as status bar -** Parmeters: (EngineState *) s: The affected game state -** (gfxw_port_t *) status_bar: The status bar port -** (char *) text: The text to draw -** Returns : (void) -*/ - -gfxw_port_t *sciw_new_window(EngineState *s, rect_t area, int font, gfx_color_t color, gfx_color_t bgcolor, - int title_font, gfx_color_t title_color, gfx_color_t title_bg_color, - const char *title, int flags); -/* Creates a new SCI style window -** Parameters: (EngineState *) s: The affected game state -** (rect_t) area: The screen area to frame (not including a potential window title) -** (int) font: Default font number to use -** (gfx_color_t) color: The foreground color to use for drawing -** (gfx_color_t) bgcolor: The background color to use -** (int) title_font: The font to use for the title bar (if any) -** (gfx_color_t) title_color: Color to use for the title bar text -** (gfx_color_t) title_bg_color: Color to use for the title bar background -** (const char *) title: The text to write into the title bar -** (int) flags: Any ORred combination of window flags -** Returns : (gfxw_port_t *) A newly allocated port with the requested characteristics -*/ - -/*---------------------*/ -/*** Control widgets ***/ -/*---------------------*/ - -gfxw_list_t *sciw_new_button_control(gfxw_port_t *port, reg_t ID, rect_t zone, char *text, int font, char selected, char inverse, char gray); -/* Creates a new button control list -** Parameters: (gfxw_port_t *) port: The port containing the color values to use for the -** button (the button is /not/ appended to the port there) -** (reg_t) ID: Button's ID -** (rect_t) zone: The area occupied by the button -** (char *) text: The text to write into the button -** (int) font: The font to use for the button -** (char) selected: Whether the button should be marked as being selected by the keyboard focus -** (char) inverse: Whether to inverse the color scheme -** (char) gray: Whether the button should be grayed out -** Returns : (gfxw_list_t *) The button -*/ - -gfxw_list_t *sciw_new_text_control(gfxw_port_t *port, reg_t ID, rect_t zone, char *text, int font, - gfx_alignment_t align, char frame, char inverse); -/* Creates a new text control list -** Parameters: (gfxw_port_t *) port: The port containing the color values to use -** (reg_t) ID: Text widget ID -** (rect_t) zone: Area occupied by the text -** (char *) text: The text -** (int) font: The font the text is to be drawn in -** (gfx_alignment_t) align: Horizontal text alignment to use -** (char) frame: Whether a dithered frame should surround the text -** (char) inverse: Whether the text colors should be inversed -** Returns : (gfxw_list_t *) The text control widget list -*/ - -gfxw_list_t *sciw_new_edit_control(gfxw_port_t *port, reg_t ID, rect_t zone, char *text, int font, unsigned int cursor, - char inverse); -/* Creates a new edit control list -** Parameters: (gfxw_port_t *) port: The port containing the color values to use -** (reg_t) ID: Text widget ID -** (rect_t) zone: Area occupied by the text -** (char *) text: The text -** (int) font: The font the text is to be drawn in -** (int) cursor: Cursor position -** (char) inverse: Whether the edit widget should be reversed -** Returns : (gfxw_list_t *) An appropriate widget list -*/ - -gfxw_list_t *sciw_new_icon_control(gfxw_port_t *port, reg_t ID, rect_t zone, int view, int loop, int cel, - char frame, char inverse); -/* Creates a new icon control list -** Parameters: (gfxw_port_t *) port: The port containing the color values to use -** (reg_t) ID: Text widget ID -** (rect_t) zone: Area occupied by the text -** (int x int x int) view, loop, cel: The cel to display -** (char) frame: Whether the widget should be surrounded by a frame -** (char) lina inverse: Whether colors should be inversed -** Returns : (gfxw_list_t *) An appropriate widget list -*/ - -gfxw_list_t *sciw_new_list_control(gfxw_port_t *port, reg_t ID, rect_t zone, int font_nr, char **entries_list, - int entries_nr, int list_top, int selection, char inverse); -/* Creates a new list control list -** Parameters: (gfxw_port_t *) port: The port containing the color values to use -** (int) ID: Text widget ID -** (rect_t) zone: Area occupied by the text -** (int) font_nr: number of the font to use -** (char **) entries_list: List of strings to contain within the list -** (int) entries_nr: Number of entries in entries_list -** (int) list_top: First list item that is visible -** (int) selection: The list item that is selected -** (char) invserse: The usual meaning -** Returns : (gfxw_list_t *) An appropriate widget list -*/ - -/*---------------------*/ -/*** Menubar widgets ***/ -/*---------------------*/ - -void sciw_set_menubar(EngineState *s, gfxw_port_t *status_bar, menubar_t *menubar, int selection); -/* Draws the menu bar -** Parameters: (EngineState *) s: The state to operate on -** (gfxw_port_t *) status_bar: The status bar port to modify -** (menubar_t *) menubar: The menu bar to use -** (int) selection: Number of the menu to hightlight, or -1 for 'none' -** Returns : (void) -*/ - -gfxw_port_t *sciw_new_menu(EngineState *s, gfxw_port_t *status_bar, menubar_t *menubar, int selection); -/* Creates a menu port -** Parameters: (EngineState *) s: The state to operate on -** (gfxw_port_t *) status_bar: The status bar -** (menubar_t *) menubar: The menu bar to use -** (int) selection: Number of the menu to interpret -** Returns : (gfxw_port_t *) The result port -*/ - -gfxw_port_t *sciw_unselect_item(EngineState *s, gfxw_port_t *menu_port, menu_t *menu, int selection); -/* Unselects a previously selected item from a menu port -** Parameters: (EngineState *) s: The state to operate on -** (gfxw_port_t *) menu_port: The port modify -** (menu_t *) menu: The menu the menu port corresponds to -** (int) selection: Number of the menu entry to unselect, or -1 to do a NOP -** Returns : (gfxw_port_t *) The modified menu -*/ - -gfxw_port_t * -sciw_select_item(EngineState *s, gfxw_port_t *menu_port, menu_t *menu, int selection); -/* Selects a menu item from a menu port -** Parameters: (EngineState *) s: The state to operate on -** (gfxw_port_t *) menu_port: The port modify -** (menu_t *) menu: The menu the menu port corresponds to -** (int) selection: Number of the menu entry to select, or -1 to do a NOP -** Returns : (gfxw_port_t *) The modified menu -*/ - -} // End of namespace Sci - -#endif // SCI_INCLUDE_SCI_WIDGETS_H diff --git a/engines/sci/module.mk b/engines/sci/module.mk index 8803549f3d..963316a01d 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -38,12 +38,12 @@ MODULE_OBJS = \ gfx/gfx_resource.o \ gfx/gfx_support.o \ gfx/gfx_tools.o \ + gfx/gfx_widgets.o \ gfx/menubar.o \ gfx/operations.o \ gfx/resmgr.o \ gfx/sbtree.o \ gfx/sci_widgets.o \ - gfx/widgets.o \ gfx/resource/sci_cursor_0.o \ gfx/resource/sci_font.o \ gfx/resource/sci_pal_1.o \ diff --git a/engines/sci/scicore/sciconsole.h b/engines/sci/scicore/sciconsole.h index 8aae95ce76..8ea75cc053 100644 --- a/engines/sci/scicore/sciconsole.h +++ b/engines/sci/scicore/sciconsole.h @@ -39,7 +39,7 @@ #include "sci/include/vm_types.h" #define SCI_CONSOLE -#include "sci/gfx/gfx_operations.h" +#include "sci/gfx/operations.h" namespace Sci { -- cgit v1.2.3