break;
case GDI_TEXT_VALUE:
- strcpy(new_gadget->text_value, va_arg(ap, char *));
+ {
+ int max_textsize = MAX_GADGET_TEXTSIZE;
+
+ if (new_gadget->text_size)
+ max_textsize = MIN(new_gadget->text_size, MAX_GADGET_TEXTSIZE - 1);
+
+ strncpy(new_gadget->text_value, va_arg(ap, char *), max_textsize);
+ new_gadget->text_value[max_textsize] = '\0';
+ }
+ break;
+
+ case GDI_TEXT_SIZE:
+ {
+ int tag_value = va_arg(ap, int);
+ int max_textsize = MIN(tag_value, MAX_GADGET_TEXTSIZE - 1);
+
+ new_gadget->text_size = max_textsize;
+ new_gadget->text_value[max_textsize] = '\0';
+
+ if (new_gadget->width == 0 && new_gadget->height == 0)
+ {
+ new_gadget->width = (new_gadget->text_size + 1) * FONT2_XSIZE + 6;
+ new_gadget->height = ED_WIN_COUNT_YSIZE;
+ }
+ }
+ break;
+
+ case GDI_TEXT_BORDER:
+ new_gadget->text_border = va_arg(ap, int);
break;
case GDI_DESIGN_UNPRESSED:
&gi->alt_design[state] :
&gi->design[state]);
- if (gi->type != GD_TYPE_NORMAL_BUTTON &&
- gi->type != GD_TYPE_RADIO_BUTTON)
- return;
+ switch (gi->type)
+ {
+ case GD_TYPE_NORMAL_BUTTON:
+ case GD_TYPE_RADIO_BUTTON:
+ XCopyArea(display, gd->pixmap, drawto, gc,
+ gd->x, gd->y, gi->width, gi->height, gi->x, gi->y);
+ break;
- XCopyArea(display, gd->pixmap, drawto, gc,
- gd->x, gd->y, gi->width, gi->height, gi->x, gi->y);
+ case GD_TYPE_TEXTINPUT:
+ {
+ int i;
+
+ /* left part of gadget */
+ XCopyArea(display, gd->pixmap, drawto, gc,
+ gd->x, gd->y,
+ gi->text_border, gi->height,
+ gi->x, gi->y);
+
+ /* middle part of gadget */
+ for (i=0; i<=gi->text_size; i++)
+ XCopyArea(display, gd->pixmap, drawto, gc,
+ gd->x + gi->text_border, gd->y,
+ FONT2_XSIZE, gi->height,
+ gi->x + gi->text_border + i * FONT2_XSIZE, gi->y);
+
+ /* right part of gadget */
+ XCopyArea(display, gd->pixmap, drawto, gc,
+ gd->x + ED_WIN_COUNT_XSIZE - gi->text_border, gd->y,
+ gi->text_border, gi->height,
+ gi->x + gi->width - gi->text_border, gi->y);
+
+ /* gadget text value */
+ DrawText(gi->x + gi->text_border, gi->y + gi->text_border,
+ gi->text_value, FS_SMALL, (pressed ? FC_GREEN : FC_YELLOW));
+
+ /* draw cursor, if active */
+ DrawText(gi->x + gi->text_border + strlen(gi->text_value)*FONT2_XSIZE,
+ gi->y + gi->text_border,
+ (pressed ? "<" : " "),
+ FS_SMALL, FC_RED);
+ }
+ break;
+
+ default:
+ return;
+ }
if (direct)
XCopyArea(display, drawto, window, gc,
gi->mapped = FALSE;
}
+static struct GadgetInfo *last_gi = NULL;
+
void HandleGadgets(int mx, int my, int button)
{
- static struct GadgetInfo *last_gi = NULL;
static unsigned long pressed_delay = 0;
struct GadgetInfo *new_gi, *gi;
boolean gadget_released;
boolean gadget_released_off_borders;
- if (gadget_list_first_entry == NULL)
+ if (gadget_list_first_entry == NULL) /* no gadgets defined */
return;
new_gi = getGadgetInfoFromMousePosition(mx, my);
+ /* if mouse button pressed outside text input gadget, deactivate it */
+ if (last_gi && last_gi->type == GD_TYPE_TEXTINPUT &&
+ button != 0 && new_gi != last_gi && !motion_status)
+ {
+ struct GadgetInfo *gi = last_gi;
+
+ DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
+
+ if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
+ gi->callback(gi);
+
+ last_gi = NULL;
+ }
+
gadget_pressed =
(button != 0 && last_gi == NULL && new_gi != NULL && !motion_status);
gadget_pressed_repeated =
gadget_released_off_borders =
(button == 0 && last_gi != NULL && new_gi != last_gi);
+ /* if new gadget pressed, store this gadget */
if (gadget_pressed)
last_gi = new_gi;
+ /* 'gi' is actually handled gadget */
gi = last_gi;
- if (button == 0)
+ /* if mouse button released, no gadget needs to be handled anymore */
+ if (button == 0 && last_gi && last_gi->type != GD_TYPE_TEXTINPUT)
last_gi = NULL;
if (gi)
if (gadget_moving_off_borders)
{
- if (gi->state == GD_BUTTON_PRESSED)
+ if (gi->state == GD_BUTTON_PRESSED &&
+ gi->type != GD_TYPE_TEXTINPUT)
DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
gi->state = GD_BUTTON_UNPRESSED;
if (gadget_released)
{
- DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
+ if (gi->type != GD_TYPE_TEXTINPUT)
+ DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
gi->state = GD_BUTTON_UNPRESSED;
gi->event.type = GD_EVENT_RELEASED;
gi->callback(gi);
}
}
+
+void HandleGadgetsKeyInput(KeySym key)
+{
+ struct GadgetInfo *gi = last_gi;
+ int text_length;
+ char letter;
+
+ if (gi == NULL || gi->type != GD_TYPE_TEXTINPUT)
+ return;
+
+ text_length = strlen(gi->text_value);
+ letter = getCharFromKeySym(key);
+
+ if (letter && text_length < gi->text_size)
+ {
+ gi->text_value[text_length] = letter;
+ gi->text_value[text_length + 1] = '\0';
+ DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+ }
+ else if ((key == XK_Delete || key == XK_BackSpace) && text_length > 0)
+ {
+ gi->text_value[text_length - 1] = '\0';
+ DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+ }
+ else if (key == XK_Return)
+ {
+ DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
+
+ if (gi->event_mask & GD_EVENT_TEXT_RETURN)
+ gi->callback(gi);
+
+ last_gi = NULL;
+ }
+}
#define GD_EVENT_MOVING (1<<2)
#define GD_EVENT_REPEATED (1<<3)
#define GD_EVENT_OFF_BORDERS (1<<4)
+#define GD_EVENT_TEXT_RETURN (1<<5)
+#define GD_EVENT_TEXT_LEAVING (1<<6)
/* gadget button states */
#define GD_BUTTON_UNPRESSED 0
#define GDI_NUMBER_MIN 11
#define GDI_NUMBER_MAX 12
#define GDI_TEXT_VALUE 13
-#define GDI_DESIGN_UNPRESSED 14
-#define GDI_DESIGN_PRESSED 15
-#define GDI_ALT_DESIGN_UNPRESSED 16
-#define GDI_ALT_DESIGN_PRESSED 17
-#define GDI_EVENT_MASK 18
-#define GDI_EVENT 19
-#define GDI_CALLBACK 20
-#define GDI_AREA_SIZE 21
-#define GDI_ITEM_SIZE 22
+#define GDI_TEXT_SIZE 14
+#define GDI_TEXT_BORDER 15
+#define GDI_DESIGN_UNPRESSED 16
+#define GDI_DESIGN_PRESSED 17
+#define GDI_ALT_DESIGN_UNPRESSED 18
+#define GDI_ALT_DESIGN_PRESSED 19
+#define GDI_EVENT_MASK 20
+#define GDI_EVENT 21
+#define GDI_CALLBACK 22
+#define GDI_AREA_SIZE 23
+#define GDI_ITEM_SIZE 24
typedef void (*gadget_callback_function)(void *);
boolean mapped; /* gadget is active */
long number_value;
char text_value[MAX_GADGET_TEXTSIZE];
+ int text_size; /* maximal size of input text */
+ int text_border; /* border size of text input gadget */
struct GadgetDesign design[2]; /* 0: normal; 1: pressed */
struct GadgetDesign alt_design[2]; /* alternative design */
unsigned long event_mask; /* possible events for this gadget */
void UnmapGadget(struct GadgetInfo *);
void HandleGadgets(int, int, int);
+void HandleGadgetsKeyInput(KeySym);
#endif
#define ED_CTRL_ID_ELEMCONT_7 34
#define ED_CTRL_ID_AMOEBA_CONTENT 35
-#define ED_NUM_GADGETS 36
+/* text input identifiers */
+#define ED_CTRL_ID_LEVEL_NAME 36
+
+#define ED_NUM_GADGETS 37
/* values for counter gadgets */
#define ED_COUNTER_SCORE 0
static void DrawDrawingWindow();
static void DrawPropertiesWindow();
static void CopyLevelToUndoBuffer();
-static void HandleDrawingAreas(struct GadgetInfo *);
-static void HandleCounterButtons(struct GadgetInfo *);
static void HandleControlButtons(struct GadgetInfo *);
+static void HandleCounterButtons(struct GadgetInfo *);
+static void HandleDrawingAreas(struct GadgetInfo *);
+static void HandleTextInputGadgets(struct GadgetInfo *);
static struct GadgetInfo *level_editor_gadget[ED_NUM_GADGETS];
static boolean level_editor_gadgets_created = FALSE;
level_editor_gadget[id] = gi;
}
+static void CreateTextInputGadgets()
+{
+ Pixmap gd_pixmap = pix[PIX_DOOR];
+ int gd_x, gd_y;
+ struct GadgetInfo *gi;
+ unsigned long event_mask;
+ int id;
+
+ gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
+ gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
+ event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
+
+ /* text input gadget for the level name */
+ id = ED_CTRL_ID_LEVEL_NAME;
+ gi = CreateGadget(GDI_CUSTOM_ID, id,
+ GDI_X, SX + ED_COUNT_ELEMCONT_XPOS,
+ GDI_Y, SY + ED_AREA_ELEMCONT_YPOS + 3 * TILEX,
+ GDI_TYPE, GD_TYPE_TEXTINPUT,
+ GDI_TEXT_VALUE, level.name,
+ GDI_TEXT_SIZE, 30,
+ GDI_TEXT_BORDER, 3,
+ GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x, gd_y,
+ GDI_DESIGN_PRESSED, gd_pixmap, gd_x, gd_y,
+ GDI_EVENT_MASK, event_mask,
+ GDI_CALLBACK, HandleTextInputGadgets,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ level_editor_gadget[id] = gi;
+}
+
static void CreateLevelEditorGadgets()
{
if (level_editor_gadgets_created)
CreateControlButtons();
CreateCounterButtons();
CreateDrawingAreas();
+ CreateTextInputGadgets();
level_editor_gadgets_created = TRUE;
}
MapGadget(level_editor_gadget[id]);
}
+static void MapTextInputGadget(int id)
+{
+ MapGadget(level_editor_gadget[id]);
+}
+
static void MapMainDrawingArea()
{
MapDrawingArea(ED_CTRL_ID_DRAWING_LEVEL);
else
DrawElementContentAreas();
}
+
+ /* TEST ONLY: level name text input gadget */
+ MapTextInputGadget(ED_CTRL_ID_LEVEL_NAME);
}
static void swap_numbers(int *i1, int *i2)
int new_element;
int button = gi->event.button;
int sx = gi->event.x, sy = gi->event.y;
+ int min_sx = 0, min_sy = 0;
+ int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
int lx, ly;
+ int min_lx = 0, min_ly = 0;
+ int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
int x, y;
/*
button_press_event = (gi->event.type == GD_EVENT_PRESSED);
button_release_event = (gi->event.type == GD_EVENT_RELEASED);
+ /* make sure to stay inside drawing area boundaries */
+ sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
+ sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
+
if (draw_level)
{
- sx = (sx < 0 ? 0 : sx > 2*SCR_FIELDX - 1 ? 2*SCR_FIELDX - 1 : sx);
- sy = (sy < 0 ? 0 : sy > 2*SCR_FIELDY - 1 ? 2*SCR_FIELDY - 1 : sy);
+ /* get positions inside level field */
lx = sx + level_xpos;
ly = sy + level_ypos;
- lx = (lx < 0 ? 0 : lx > lev_fieldx - 1 ? lev_fieldx - 1 : lx);
- ly = (ly < 0 ? 0 : ly > lev_fieldy - 1 ? lev_fieldy - 1 : ly);
+ /* make sure to stay inside level field boundaries */
+ lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
+ ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
+
+ /* correct drawing area positions accordingly */
sx = lx - level_xpos;
sy = ly - level_ypos;
}
- else
- {
- sx = (sx < 0 ? 0 : sx > 2 ? 2 : sx);
- sy = (sy < 0 ? 0 : sy > 2 ? 2 : sy);
- }
if (button_press_event)
started_inside_drawing_area = inside_drawing_area;
{
if (edit_mode == ED_MODE_DRAWING && drawing_function == ED_CTRL_ID_TEXT)
{
- char *keyname = getKeyNameFromKeySym(key);
- char letter = 0;
-
- if (strlen(keyname) == 1)
- letter = keyname[0];
- else if (strcmp(keyname, "space") == 0)
- letter = ' ';
- else if (strcmp(keyname, "less") == 0)
- letter = '<';
- else if (strcmp(keyname, "equal") == 0)
- letter = '=';
- else if (strcmp(keyname, "greater") == 0)
- letter = '>';
+ char letter = getCharFromKeySym(key);
/* map lower case letters to upper case */
if (letter >= 'a' && letter <= 'z')
DrawLevelText(0, 0, 0, TEXT_NEWLINE);
}
}
+
+
+static void HandleTextInputGadgets(struct GadgetInfo *gi)
+{
+ int id = gi->custom_id;
+
+ switch (id)
+ {
+ case ED_CTRL_ID_LEVEL_NAME:
+ strcpy(level.name, gi->text_value);
+ break;
+
+ default:
+ break;
+ }
+}
+ HandleGadgetsKeyInput(key);
+
switch(game_status)
{
case TYPENAME:
#define MINI_MORE_STARTX 0
#define MINI_MORE_STARTY 160
#define MICRO_MORE_STARTX 0
-#define MICRO_MORE_STARTY 208
+#define MICRO_MORE_STARTY 240
#define MORE_PER_LINE 16
#define MINI_MORE_PER_LINE 16
#define MICRO_MORE_PER_LINE 16
return keysym;
}
+char getCharFromKeySym(KeySym keysym)
+{
+ char *keyname = getKeyNameFromKeySym(keysym);
+ char letter = 0;
+
+ if (strlen(keyname) == 1)
+ letter = keyname[0];
+ else if (strcmp(keyname, "space") == 0)
+ letter = ' ';
+ else if (strcmp(keyname, "less") == 0)
+ letter = '<';
+ else if (strcmp(keyname, "equal") == 0)
+ letter = '=';
+ else if (strcmp(keyname, "greater") == 0)
+ letter = '>';
+
+ return letter;
+}
+
#define TRANSLATE_JOYSYMBOL_TO_JOYNAME 0
#define TRANSLATE_JOYNAME_TO_JOYSYMBOL 1
char *getKeyNameFromKeySym(KeySym);
char *getX11KeyNameFromKeySym(KeySym);
KeySym getKeySymFromX11KeyName(char *);
+char getCharFromKeySym(KeySym);
char *getJoyNameFromJoySymbol(int);
int getJoySymbolFromJoyName(char *);
int getJoystickNrFromDeviceName(char *);