1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-08 18:14:21 +03:00
inform7/inter/index-module/Chapter 4/Map Configuration.w

264 lines
10 KiB
OpenEdge ABL
Raw Normal View History

2021-06-27 18:04:28 +03:00
[ConfigureIndexMap::] Map Configuration.
2021-06-22 01:37:27 +03:00
2021-06-27 18:04:28 +03:00
To manage configuration parameters for the EPS and HTML maps.
2021-06-22 01:37:27 +03:00
2021-07-26 01:56:17 +03:00
@ The EPS map-maker is really a miniature interpreted programming language in
its own right, and here we define that language's data types and variables.
2021-06-22 01:37:27 +03:00
2021-07-26 01:56:17 +03:00
The "mapping parameters" amount to being variables. The following structure
defines the type and current value for each variable: see the Inform
documentation for details. But note that variables of the same name are held by
many different objects in the map, and their values inherited by sub-objects.
2021-06-22 01:37:27 +03:00
@d INT_MDT 1 /* an integer */
@d BOOL_MDT 2 /* true or false */
@d TEXT_MDT 3 /* quoted text */
@d COL_MDT 4 /* an HTML-safe colour */
@d FONT_MDT 5 /* the name of a font */
@d OFF_MDT 6 /* a positional offset in an $(x,y)$ grid */
=
typedef struct plotting_parameter {
int specified; /* is it explicitly specified at this scope? */
2021-06-27 16:56:29 +03:00
struct text_stream *name; /* name (used only in global scope) */
wchar_t *name_init; /* name (used only in global scope) */
2021-06-22 01:37:27 +03:00
int parameter_data_type; /* one of the above types (used only in global scope) */
2021-06-27 16:56:29 +03:00
struct text_stream *textual_value; /* string value, if appropriate to this type; */
wchar_t *textual_value_init; /* string value, if appropriate to this type; */
2021-06-22 01:37:27 +03:00
int numeric_value; /* or numeric value, if appropriate to this type */
} plotting_parameter;
2021-07-26 01:56:17 +03:00
@ A set of variables associated with any map object is called a "scope". As
implied above, the global scope is special: it contains the default settings
passed down to all lower scopes.
2021-06-22 01:37:27 +03:00
2021-06-27 16:56:29 +03:00
@d NO_MAP_PARAMETERS 34
2021-06-22 01:37:27 +03:00
=
typedef struct map_parameter_scope {
struct map_parameter_scope *wider_scope; /* that is, the scope above this */
struct plotting_parameter values[NO_MAP_PARAMETERS];
} map_parameter_scope;
2021-07-27 02:42:09 +03:00
map_parameter_scope initial_global_map_scope = {
2021-06-22 01:37:27 +03:00
NULL,
{
2021-06-27 16:56:29 +03:00
{ TRUE, NULL, L"font", FONT_MDT, NULL, L"Helvetica", 0 },
{ TRUE, NULL, L"minimum-map-width", INT_MDT, NULL, NULL, 72*5 },
{ TRUE, NULL, L"title", TEXT_MDT, NULL, L"Map", 0 },
{ TRUE, NULL, L"title-size", INT_MDT, NULL, NULL, 24 },
{ TRUE, NULL, L"title-font", FONT_MDT, NULL, L"<font>", 0 },
{ TRUE, NULL, L"title-colour", COL_MDT, NULL, L"000000", 0 },
{ TRUE, NULL, L"map-outline", BOOL_MDT, NULL, NULL, 1 },
{ TRUE, NULL, L"border-size", INT_MDT, NULL, NULL, 12 },
{ TRUE, NULL, L"vertical-spacing", INT_MDT, NULL, NULL, 6 },
{ TRUE, NULL, L"monochrome", BOOL_MDT, NULL, NULL, 0 },
{ TRUE, NULL, L"annotation-size", INT_MDT, NULL, NULL, 8 },
{ TRUE, NULL, L"annotation-length", INT_MDT, NULL, NULL, 8 },
{ TRUE, NULL, L"annotation-font", FONT_MDT, NULL, L"<font>", 0 },
{ TRUE, NULL, L"subtitle", TEXT_MDT, NULL, L"Map", 0 },
{ TRUE, NULL, L"subtitle-size", INT_MDT, NULL, NULL, 16 },
{ TRUE, NULL, L"subtitle-font", FONT_MDT, NULL, L"<font>", 0 },
{ TRUE, NULL, L"subtitle-colour", COL_MDT, NULL, L"000000", 0 },
{ TRUE, NULL, L"grid-size", INT_MDT, NULL, NULL, 72 },
{ TRUE, NULL, L"route-stiffness", INT_MDT, NULL, NULL, 100 },
{ TRUE, NULL, L"route-thickness", INT_MDT, NULL, NULL, 1 },
{ TRUE, NULL, L"route-colour", COL_MDT, NULL, L"000000", 0 },
{ TRUE, NULL, L"room-offset", OFF_MDT, NULL, NULL, 0 },
{ TRUE, NULL, L"room-size", INT_MDT, NULL, NULL, 36 },
{ TRUE, NULL, L"room-colour", COL_MDT, NULL, L"DDDDDD", 0 },
{ TRUE, NULL, L"room-name", TEXT_MDT, NULL, L"", 0 },
{ TRUE, NULL, L"room-name-size", INT_MDT, NULL, NULL, 12 },
{ TRUE, NULL, L"room-name-font", FONT_MDT, NULL, L"<font>", 0 },
{ TRUE, NULL, L"room-name-colour", COL_MDT, NULL, L"000000", 0 },
{ TRUE, NULL, L"room-name-length", INT_MDT, NULL, NULL, 5 },
{ TRUE, NULL, L"room-name-offset", OFF_MDT, NULL, NULL, 0 },
{ TRUE, NULL, L"room-outline", BOOL_MDT, NULL, NULL, 1 },
{ TRUE, NULL, L"room-outline-colour", COL_MDT, NULL, L"000000", 0 },
2021-07-26 01:56:17 +03:00
{ TRUE, NULL, L"room-outline-thickness",INT_MDT, NULL, NULL, 1 },
2021-06-27 16:56:29 +03:00
{ TRUE, NULL, L"room-shape", TEXT_MDT, NULL, L"square", 0 }
2021-06-22 01:37:27 +03:00
}
};
2021-07-27 02:42:09 +03:00
int ConfigureIndexMap::type_of_parameter(int index_of_parameter) {
return initial_global_map_scope.values[index_of_parameter].parameter_data_type;
}
2021-07-26 01:56:17 +03:00
@ A little dynamic initialisation is needed here, because |I"whatever"| constants
are not in fact legal in constant context in C. So those |L"whatever"| values,
which are legal, are converted to to |I"whatever"| values here:
=
2021-07-27 02:42:09 +03:00
map_parameter_scope ConfigureIndexMap::global_settings(void) {
for (int p=0; p<NO_MAP_PARAMETERS; p++) {
2021-07-27 15:55:53 +03:00
initial_global_map_scope.values[p].name = Str::new();
WRITE_TO(initial_global_map_scope.values[p].name, "%w",
initial_global_map_scope.values[p].name_init);
initial_global_map_scope.values[p].textual_value = Str::new();
if (initial_global_map_scope.values[p].textual_value_init)
WRITE_TO(initial_global_map_scope.values[p].textual_value, "%w",
initial_global_map_scope.values[p].textual_value_init);
2021-06-27 16:56:29 +03:00
}
2021-07-27 15:55:53 +03:00
return initial_global_map_scope;
2021-06-27 16:56:29 +03:00
}
2021-07-26 01:56:17 +03:00
@ Non-global scopes are initialised here, though it's a much simpler process
because everything starts out blank.
2021-06-22 01:37:27 +03:00
=
2021-07-27 02:42:09 +03:00
void ConfigureIndexMap::prepare_map_parameter_scope(map_parameter_scope *scope,
index_session *session) {
scope->wider_scope = Indexing::get_global_map_scope(session);
2021-07-26 01:56:17 +03:00
for (int s=0; s<NO_MAP_PARAMETERS; s++) {
scope->values[s].specified = FALSE;
scope->values[s].name = NULL;
scope->values[s].textual_value = NULL;
scope->values[s].numeric_value = 0;
}
}
2021-06-22 01:37:27 +03:00
2021-07-26 01:56:17 +03:00
@ We convert a parameter's name to its index in the list; slowly, but that
2021-06-22 01:37:27 +03:00
doesn't matter.
=
2021-07-27 02:42:09 +03:00
int ConfigureIndexMap::get_map_variable_index(text_stream *name, index_session *session) {
int s = ConfigureIndexMap::get_map_variable_index_forgivingly(name, session);
2021-06-22 01:37:27 +03:00
if (s < 0) {
2021-06-27 16:56:29 +03:00
LOG("Tried to look up <%S>\n", name);
2021-06-22 01:37:27 +03:00
internal_error("looked up non-existent map variable");
}
return s;
}
2021-06-27 18:04:28 +03:00
int ConfigureIndexMap::get_map_variable_index_from_wchar(wchar_t *wc_name) {
2021-07-27 02:42:09 +03:00
for (int s=0; s<NO_MAP_PARAMETERS; s++)
if ((initial_global_map_scope.values[s].name_init) &&
(Wide::cmp(wc_name, initial_global_map_scope.values[s].name_init) == 0))
return s;
return -1;
2021-06-27 16:56:29 +03:00
}
2021-07-27 02:42:09 +03:00
int ConfigureIndexMap::get_map_variable_index_forgivingly(text_stream *name,
index_session *session) {
2021-06-22 01:37:27 +03:00
for (int s=0; s<NO_MAP_PARAMETERS; s++)
2021-07-27 02:42:09 +03:00
if ((Indexing::get_global_map_scope(session)->values[s].name) &&
(Str::cmp(name, Indexing::get_global_map_scope(session)->values[s].name) == 0))
2021-06-22 01:37:27 +03:00
return s;
return -1;
}
@ The following sets a parameter to a given value (the string value if that's
non-|NULL|, the number value otherwise), for a particular scope: this is
slightly wastefully specified either as a |map_parameter_scope| object,
or as a single room, or as a single region, or as a kind of room or region.
If all are null, then the global scope is used.
=
2021-07-26 01:56:17 +03:00
void ConfigureIndexMap::put_mp(text_stream *name, map_parameter_scope *scope,
2021-07-27 02:42:09 +03:00
faux_instance *scope_I, text_stream *put_string, int put_integer, index_session *session) {
2021-06-22 22:37:53 +03:00
if (scope == NULL) {
2021-07-27 02:42:09 +03:00
if (scope_I == NULL) scope = Indexing::get_global_map_scope(session);
else scope = FauxInstances::get_parameters(scope_I);
2021-06-22 01:37:27 +03:00
}
2021-06-27 16:56:29 +03:00
if (Str::cmp(name, I"room-colour") == 0) {
2021-07-27 15:55:53 +03:00
if (scope == Indexing::get_global_map_scope(session))
session->changed_global_room_colour = TRUE;
2021-06-22 22:37:53 +03:00
if (scope_I) scope_I->fimd.colour = put_string;
2021-06-22 01:37:27 +03:00
}
2021-06-27 16:56:29 +03:00
if (Str::cmp(name, I"room-name-colour") == 0)
2021-06-22 22:37:53 +03:00
if (scope_I) scope_I->fimd.text_colour = put_string;
2021-07-27 02:42:09 +03:00
if (put_string) ConfigureIndexMap::put_text_mp(name, scope, put_string, session);
else ConfigureIndexMap::put_int_mp(name, scope, put_integer, session);
2021-06-22 01:37:27 +03:00
}
2021-07-26 01:56:17 +03:00
@ Text parameters.
2021-06-22 01:37:27 +03:00
=
2021-07-27 02:42:09 +03:00
text_stream *ConfigureIndexMap::get_text_mp(text_stream *name, map_parameter_scope *scope,
index_session *session) {
int s = ConfigureIndexMap::get_map_variable_index(name, session);
if (scope == NULL) scope = Indexing::get_global_map_scope(session);
2021-06-22 01:37:27 +03:00
while (scope->values[s].specified == FALSE) {
scope = scope->wider_scope;
if (scope == NULL) internal_error("scope exhausted in looking up map parameter");
}
2021-07-27 15:55:53 +03:00
if ((Str::ne(name, I"font")) && (Str::eq(scope->values[s].textual_value, I"<font>")))
return ConfigureIndexMap::get_text_mp(I"font", NULL, session);
2021-06-27 16:56:29 +03:00
return scope->values[s].textual_value;
2021-06-22 01:37:27 +03:00
}
2021-07-26 01:56:17 +03:00
void ConfigureIndexMap::put_text_mp(text_stream *name, map_parameter_scope *scope,
2021-07-27 02:42:09 +03:00
text_stream *val, index_session *session) {
int s = ConfigureIndexMap::get_map_variable_index(name, session);
if (scope == NULL) scope = Indexing::get_global_map_scope(session);
2021-06-22 01:37:27 +03:00
scope->values[s].specified = TRUE;
2021-06-27 16:56:29 +03:00
scope->values[s].textual_value = Str::duplicate(val);
2021-06-22 01:37:27 +03:00
}
@ Integer parameters.
=
2021-07-27 02:42:09 +03:00
int ConfigureIndexMap::get_int_mp(text_stream *name, map_parameter_scope *scope,
index_session *session) {
int s = ConfigureIndexMap::get_map_variable_index(name, session);
if (scope == NULL) scope = Indexing::get_global_map_scope(session);
2021-06-22 01:37:27 +03:00
while (scope->values[s].specified == FALSE) {
scope = scope->wider_scope;
if (scope == NULL) internal_error("scope exhausted in looking up map parameter");
}
return scope->values[s].numeric_value;
}
2021-07-27 02:42:09 +03:00
void ConfigureIndexMap::put_int_mp(text_stream *name, map_parameter_scope *scope, int val,
index_session *session) {
int s = ConfigureIndexMap::get_map_variable_index(name, session);
if (scope == NULL) scope = Indexing::get_global_map_scope(session);
2021-06-22 01:37:27 +03:00
scope->values[s].specified = TRUE;
scope->values[s].numeric_value = val;
}
2021-07-26 01:56:17 +03:00
@h Rubric definitions.
A "rubric" is a freestanding piece of text written on the map. Typically
it will be a title, or "Here Be Monsters", or something like that.
=
typedef struct rubric_holder {
struct text_stream *annotation;
int point_size;
struct text_stream *font;
struct text_stream *colour;
int at_offset;
struct faux_instance *offset_from;
CLASS_DEFINITION
} rubric_holder;
@h EPS definitions.
Each horizontal level of the EPS map needs its own storage, not least to
hold the applicable mapping parameters.
=
typedef struct EPS_map_level {
int width;
int actual_height;
int height;
struct text_stream *titling;
int titling_point_size;
int map_level;
int y_max;
int y_min;
int contains_rooms;
int contains_titling;
int eps_origin;
struct map_parameter_scope map_parameters;
CLASS_DEFINITION
} EPS_map_level;
@ The following are the directions at which arrows for UP, DOWN, IN and OUT
are drawn on EPS maps.
=
vector U_vector_EPS = {2, 3, 0};
vector D_vector_EPS = {-2, -3, 0};
vector IN_vector_EPS = {3, 2, 0};
vector OUT_vector_EPS = {-3, -2, 0};