This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
magicka/deps/cdk-5.0-20161210/cdkscreen.c
2017-03-20 21:40:32 +10:00

510 lines
10 KiB
C

#include <cdk_int.h>
#ifdef HAVE_SETLOCALE
#include <locale.h>
#endif
/*
* $Author: tom $
* $Date: 2016/12/04 15:41:50 $
* $Revision: 1.91 $
*/
typedef struct _all_screens
{
struct _all_screens *link;
CDKSCREEN *screen;
}
ALL_SCREENS;
static ALL_SCREENS *all_screens;
typedef struct _all_objects
{
struct _all_objects *link;
CDKOBJS *object;
}
ALL_OBJECTS;
static ALL_OBJECTS *all_objects;
static boolean validObjType (CDKOBJS *obj, EObjectType type)
{
bool valid = FALSE;
if (obj != 0 && ObjTypeOf (obj) == type)
{
switch (type)
{
case vALPHALIST:
case vBUTTON:
case vBUTTONBOX:
case vCALENDAR:
case vDIALOG:
case vDSCALE:
case vENTRY:
case vFSCALE:
case vFSELECT:
case vFSLIDER:
case vGRAPH:
case vHISTOGRAM:
case vITEMLIST:
case vLABEL:
case vMARQUEE:
case vMATRIX:
case vMENTRY:
case vMENU:
case vRADIO:
case vSCALE:
case vSCROLL:
case vSELECTION:
case vSLIDER:
case vSWINDOW:
case vTEMPLATE:
case vUSCALE:
case vUSLIDER:
case vVIEWER:
valid = TRUE;
break;
case vTRAVERSE: /* not really an object */
case vNULL:
break;
}
}
return valid;
}
/*
* Set indices so the screen and object point to each other.
*/
static void setScreenIndex (CDKSCREEN *screen, int number, CDKOBJS *obj)
{
(obj)->screenIndex = number;
(obj)->screen = screen;
screen->object[number] = obj;
}
/*
* Returns true if we have done a "new" on this object but no "destroy"
*/
bool validCDKObject (CDKOBJS *obj)
{
bool result = FALSE;
if (obj != 0)
{
ALL_OBJECTS *ptr;
for (ptr = all_objects; ptr != 0; ptr = ptr->link)
{
if (ptr->object == obj)
{
result = validObjType (obj, ObjTypeOf (obj));
break;
}
}
}
return result;
}
/*
* Create a new object beginning with a CDKOBJS struct. The whole object is
* initialized to zeroes except for special cases which have known values.
*/
void *_newCDKObject (unsigned size, const CDKFUNCS * funcs)
{
ALL_OBJECTS *item;
CDKOBJS *result = 0;
if ((item = typeCalloc (ALL_OBJECTS)) != 0)
{
if ((result = (CDKOBJS *)calloc (1, size)) != 0)
{
result->fn = funcs;
result->hasFocus = TRUE;
result->isVisible = TRUE;
item->link = all_objects;
item->object = result;
all_objects = item;
/* set default line-drawing characters */
result->ULChar = ACS_ULCORNER;
result->URChar = ACS_URCORNER;
result->LLChar = ACS_LLCORNER;
result->LRChar = ACS_LRCORNER;
result->HZChar = ACS_HLINE;
result->VTChar = ACS_VLINE;
result->BXAttr = A_NORMAL;
/* set default exit-types */
result->exitType = vNEVER_ACTIVATED;
result->earlyExit = vNEVER_ACTIVATED;
}
else
{
free (item);
}
}
return (void *)result;
}
void _destroyCDKObject (CDKOBJS *obj)
{
if (validCDKObject (obj))
{
ALL_OBJECTS *p, *q;
for (p = all_objects, q = 0; p != 0; q = p, p = p->link)
{
if (p->object == obj)
{
/* delink it first, to avoid problems with recursion */
if (q != 0)
q->link = p->link;
else
all_objects = p->link;
MethodPtr (obj, destroyObj) (obj);
free (obj);
free (p);
break;
}
}
}
}
/*
* This creates a new CDK screen.
*/
CDKSCREEN *initCDKScreen (WINDOW *window)
{
ALL_SCREENS *item;
CDKSCREEN *screen = 0;
/* initialization, for the first time */
if (all_screens == 0 || stdscr == 0 || window == 0)
{
/* Set up basic curses settings. */
#ifdef HAVE_SETLOCALE
setlocale (LC_ALL, "");
#endif
/* Initialize curses after setting the locale, since curses depends
* on having a correct locale to reflect the terminal's encoding.
*/
if (stdscr == 0 || window == 0)
{
window = initscr ();
}
noecho ();
cbreak ();
}
if ((item = typeMalloc (ALL_SCREENS)) != 0)
{
if ((screen = typeCalloc (CDKSCREEN)) != 0)
{
item->link = all_screens;
item->screen = screen;
all_screens = item;
/* Initialize the CDKSCREEN pointer. */
screen->objectCount = 0;
screen->objectLimit = 2;
screen->object = typeMallocN (CDKOBJS *, screen->objectLimit);
screen->window = window;
/* OK, we are done. */
}
else
{
free (item);
}
}
return (screen);
}
/*
* This registers a CDK object with a screen.
*/
void registerCDKObject (CDKSCREEN *screen, EObjectType cdktype, void *object)
{
CDKOBJS *obj = (CDKOBJS *)object;
if (screen->objectCount + 1 >= screen->objectLimit)
{
screen->objectLimit += 2;
screen->objectLimit *= 2;
screen->object = typeReallocN (CDKOBJS *, screen->object, screen->objectLimit);
}
if (validObjType (obj, cdktype))
{
setScreenIndex (screen, screen->objectCount++, obj);
}
}
/*
* This registers a CDK object with a screen.
*/
void reRegisterCDKObject (EObjectType cdktype, void *object)
{
CDKOBJS *obj = (CDKOBJS *)object;
registerCDKObject (obj->screen, cdktype, object);
}
/*
* This removes an object from the CDK screen.
*/
void unregisterCDKObject (EObjectType cdktype, void *object)
{
CDKOBJS *obj = (CDKOBJS *)object;
if (validObjType (obj, cdktype) && obj->screenIndex >= 0)
{
CDKSCREEN *screen = (obj)->screen;
if (screen != 0)
{
int Index = (obj)->screenIndex;
int x;
obj->screenIndex = -1;
/*
* Resequence the objects.
*/
for (x = Index; x < screen->objectCount - 1; x++)
{
setScreenIndex (screen, x, screen->object[x + 1]);
}
if (screen->objectCount <= 1)
{
/* if no more objects, remove the array */
freeAndNull (screen->object);
screen->objectCount = 0;
screen->objectLimit = 0;
}
else
{
/* Reduce the list by one object. */
screen->object[screen->objectCount--] = 0;
/*
* Update the object-focus
*/
if (screen->objectFocus == Index)
{
screen->objectFocus--;
(void)setCDKFocusNext (screen);
}
else if (screen->objectFocus > Index)
{
screen->objectFocus--;
}
}
}
}
}
#define validIndex(screen, n) ((n) >= 0 && (n) < (screen)->objectCount)
static void swapCDKIndices (CDKSCREEN *screen, int n1, int n2)
{
if (n1 != n2 && validIndex (screen, n1) && validIndex (screen, n2))
{
CDKOBJS *o1 = screen->object[n1];
CDKOBJS *o2 = screen->object[n2];
setScreenIndex (screen, n1, o2);
setScreenIndex (screen, n2, o1);
if (screen->objectFocus == n1)
screen->objectFocus = n2;
else if (screen->objectFocus == n2)
screen->objectFocus = n1;
}
}
/*
* This 'brings' a CDK object to the top of the stack.
*/
void raiseCDKObject (EObjectType cdktype, void *object)
{
CDKOBJS *obj = (CDKOBJS *)object;
if (validObjType (obj, cdktype))
{
CDKSCREEN *screen = obj->screen;
swapCDKIndices (screen, obj->screenIndex, screen->objectCount - 1);
}
}
/*
* This 'lowers' an object.
*/
void lowerCDKObject (EObjectType cdktype, void *object)
{
CDKOBJS *obj = (CDKOBJS *)object;
if (validObjType (obj, cdktype))
{
CDKSCREEN *screen = obj->screen;
swapCDKIndices (screen, obj->screenIndex, 0);
}
}
/*
* This calls refreshCDKScreen. (made consistent with widgets)
*/
void drawCDKScreen (CDKSCREEN *cdkscreen)
{
refreshCDKScreen (cdkscreen);
}
/*
* Refresh one CDK window.
* FIXME: this should be rewritten to use the panel library, so it would not
* be necessary to touch the window to ensure that it covers other windows.
*/
void refreshCDKWindow (WINDOW *win)
{
touchwin (win);
wrefresh (win);
}
/*
* This refreshes all the objects in the screen.
*/
void refreshCDKScreen (CDKSCREEN *cdkscreen)
{
int objectCount = cdkscreen->objectCount;
int x;
int focused = -1;
int visible = -1;
refreshCDKWindow (cdkscreen->window);
/* We erase all the invisible objects, then only
* draw it all back, so that the objects
* can overlap, and the visible ones will always
* be drawn after all the invisible ones are erased */
for (x = 0; x < objectCount; x++)
{
CDKOBJS *obj = cdkscreen->object[x];
if (validObjType (obj, ObjTypeOf (obj)))
{
if (obj->isVisible)
{
if (visible < 0)
visible = x;
if (obj->hasFocus && focused < 0)
focused = x;
}
else
{
obj->fn->eraseObj (obj);
}
}
}
for (x = 0; x < objectCount; x++)
{
CDKOBJS *obj = cdkscreen->object[x];
if (validObjType (obj, ObjTypeOf (obj)))
{
obj->hasFocus = (x == focused);
if (obj->isVisible)
{
obj->fn->drawObj (obj, obj->box);
}
}
}
}
/*
* This clears all the objects in the screen.
*/
void eraseCDKScreen (CDKSCREEN *cdkscreen)
{
int objectCount = cdkscreen->objectCount;
int x;
/* We just call the drawObject function. */
for (x = 0; x < objectCount; x++)
{
CDKOBJS *obj = cdkscreen->object[x];
if (validObjType (obj, ObjTypeOf (obj)))
{
obj->fn->eraseObj (obj);
}
}
/* Refresh the screen. */
wrefresh (cdkscreen->window);
}
/*
* Destroy all of the objects on a screen
*/
void destroyCDKScreenObjects (CDKSCREEN *cdkscreen)
{
int x;
for (x = 0; x < cdkscreen->objectCount; x++)
{
CDKOBJS *obj = cdkscreen->object[x];
int before = cdkscreen->objectCount;
if (validObjType (obj, ObjTypeOf (obj)))
{
MethodPtr (obj, eraseObj) (obj);
_destroyCDKObject (obj);
x -= (cdkscreen->objectCount - before);
}
}
}
/*
* This destroys a CDK screen.
*/
void destroyCDKScreen (CDKSCREEN *screen)
{
ALL_SCREENS *p, *q;
for (p = all_screens, q = 0; p != 0; q = p, p = p->link)
{
if (screen == p->screen)
{
if (q != 0)
q->link = p->link;
else
all_screens = p->link;
free (p);
free (screen);
break;
}
}
}
/*
* This is added to remain consistent.
*/
void endCDK (void)
{
/* Turn echoing back on. */
echo ();
/* Turn off cbreak. */
nocbreak ();
/* End the curses windows. */
endwin ();
#ifdef HAVE_XCURSES
XCursesExit ();
#endif
}