\chapter{Elementare Fenstertechnik}

\section{Ein wenig Theorie zur Fenstertechnik}

\subsection{Was ist ein Fenster?}
    Ein Fenster innerhalb der libCUI beschreibt einen rechteckigen
    Bildschirmbereich, der mit einer
    rudiment"aren Basisfunktionalit"at ausgestattet ist. Um ein Fenster an
    eine spezielle Aufgabe anzupassen wird es mit Eigenschaften und Hook-Funktionen
    versehen.

    Eigenschaften sind u.a. Fensterstile und Farben. Sie steuern haupts"achlich das
    optische Erscheinungsbild des Fensters und dessen Verhalten innerhalb
    des Fensterstapels.

    "uber Hook-Funktionen werden dem Fenster vom Fenstermanager Nachrichten
    zugesendet, auf die es durch selbstimplementierte Weise reagieren kann.
    Solche Nachrichten sind z.B. die Aufforderung zum Zeichnen des
    Fensterbereichs oder die "ubergabe von Tastatureingaben
    an das Fenster.

    "uber einen nichttypisierten Datenzeiger kann ein Fenster Instanz-Daten
    verwalten, die es f"ur seine Funktion ben"otigt.

\subsection{Lebenszyklus}
    Ein Fenster macht "ublicherweise die folgenden Stadien im Laufe seiner
    Existenz durch: Anlegen, Spezialisieren, Erzeugen und Zerst"oren.

\begin{figure}
  \includegraphics[width=6in]{pics/window1.png}
\end{figure}

    Anlegen:\\
    Das Anlegen einer neuen Fensterinstanz erfolgt mit Hilfe der Funktion
    ''WindowNew''. Dabei werden dem Fenster eine Position, eine Vater-Beziehung
    und eine Reihe von Fensterstilen mitgegeben. Das Ergebnis ist eine
    Struktur vom Typ CUIWINDOW, "uber die das Fenster in Zukunft angesprochen
    und identifiziert werden kann.

    Spezialisieren:\\
    Durch das Spezialisieren bekommt das Fenster weitere Eigenschaften (z.B.
    Farben), seine Funktionalit"at (Hook-Funktionen) und seine Instanzdaten
    beigebracht. Zu diesem Zweck gibt es eine Reihe von API-Funktionen. Siehe
    dazu u.a. den Abschnitt ''Hook Funktionen''.

    Erzeugen:\\
    Bevor ein Fenster im Fensterstapel sichtbar werden kann, muss es erzeugt
    werden. Dies erfolgt mit der Funktion ''WindowCreate''. Dabei werden die
    erforderlichen Curses-Strukturen erzeugt und das Fenster in den Fensterstapel
    eingebunden.

    Zerst"oren:\\
    Zerst"ort wird ein Fenster "uber die Funktion ''WindowDestroy''. Damit wird das
    Fenster und alle seine Kindfenster aus dem Fensterstapel entfernt. Zudem
    werden die zugeh"origen Datenstrukturen freigegeben. Das hei"st auch, dass ein
    Fenster wieder neu angelegt werden muss, bevor es erneut verwendet werden
    kann.

    Es bietet sich an, das Anlegen und Spezialisieren in einer Funktion zu
    vereinen. Eingeb"urgert hat sich dabei die Namenskonvention {\it Fenstername}New.
    Beispiele: ''EditNew'', ''LabelNew'', ''ListboxNew'' ...

\subsection{Fensterhierarchie}
    Grob unterteilt gibt es in der libCUI zwei Fensterkategorien: Popup-Fenster und
    Kindfenster.

    Kindfenster sind immer ihrem Vaterfenster untergeordnet. Die Positionierung
    erfolgt relativ zum Vaterfenster und der sichtbare Bereich wird durch den Client
    Bereich des Vaterfensters gegrenzt (Clipping).

    Popup-Fenster dagegen sind immer dem Desktopfenster untergeordnet und besitzen
    lediglich einen Besitzer- (Owner-) Verweis auf dasjenige Popup-Fenster aus dessen
    Kontext (Kindfenster) heraus das Vaterfenster angegeben wurde. Der sichtbare
    Bereich wird lediglich von weiteren "ubergeordneten Popup-Fenstern maskiert, nicht
    jedoch vom Vaterfenster.

    Fenster werden in einem Stapel hierarchisch angeordnet, wobei die Basis aller
    Fenster das Desktopfenster ist. Dieses existiert bereits nach dem Aufruf
    von ''WindowStart()'', besitzt jedoch keine besondere Funktion (au"ser der
    Darstellung einer einfarbigen Fl"ache).
    "uber dem Desktop ist der Fensterstapel angeordnet, wobei jedes Fenster vier
    Referenzen kennt: Das Vaterfenster (P = Parent), das Besitzerfenster (O = Owner),
    das n"achste Fenster in der selben Hierarchieebene (N = Next) und das erste
    Fenster in der Liste der Kindfenster (C = Child). Es ergibt sich die in der
    Abbildung dargestellte Struktur.

\begin{figure}
  \includegraphics[width=6in]{pics/window3.png}
\end{figure}

    Wird ein Fenster aus dem Fensterstapel entfernt (''WindowDestroy''), dann
    verschwinden auch s"amtliche Kindfenster von der Anzeige. Das selbe passiert
    auch dann, wenn die Sichtbarkeit eines Fensters beeinflusst wird.

    Kindfenster des Desktops sind "ubrigens immer Popup-Fenster. Dieser Stil
    wird beim Erzeugen erzwugen, wenn als Vaterfenster das Desktopfenster
    angegeben wurde.


\subsection{Bereiche eines Fensters}
    Ein Fenster in der libCUI besitzt zwei Darstellungsbereiche: Den Client Bereich
    und den Nicht-Client Bereich. Im Nicht-Client Bereich werden Fensterdekorationen
    wie z.B. ein Rahmen eine Titlezeile oder Bildlaufleisten dargestellt. Im Client
    Bereich kann ein Fenster seine Daten zur Ansicht bringen oder weitere Kindfenster
    anordnen. Jedes Fenster besitzt immer beide Bereiche. Ob der Nicht-Client Bereich
    tats"achlich sichtbar ist, wird "uber Fensterstile gesteuert.


\subsection{Beispiel}
    Anhand eines Code-Beispiels werden nun einige der vorgestellten Konzepte
    erl"autert. Das vorgestellte Programm soll ein einfaches Popup-Fenster
    (vergleichbar dem Hallo-World Programm aus dem vorigen Kapitel) zentriert
    darstellen, in dem die aktuelle Systemzeit ausgegeben wird. Hier das
    Programmlisting:

\begin{verbatim}

#include <stdlib.h>
#include <time.h>
#include <cui.h>

#define MY_TIMER 100

void quit(void)
{
   WindowEnd();
}

void MyPaintHook(void* w)
{
   CUIWINDOW* win = (CUIWINDOW*) w;
   CUIRECT    rc;
   char       tstr[64];
   time_t     ti;
   struct tm* loctime;

   WindowGetClientRect(win, &rc);

   time(&ti);

   loctime = localtime(&ti);

   sprintf(tstr, "%02i:%02i:%02i",
      loctime->tm_hour,
      loctime->tm_min,
      loctime->tm_sec);
   mvwaddstr(win->Win, rc.H / 2 - 1,
            (rc.W - strlen(tstr)) / 2, tstr);

   strcpy(tstr, "F10 = Close");
   mvwaddstr(win->Win, rc.H / 2 + 1,
            (rc.W - strlen(tstr)) / 2, tstr);
}

int MyKeyHook(void* w, int key)
{
   if (key == KEY_F(10))
   {
      if (WindowClose((CUIWINDOW*) w, EXIT_SUCCESS))
      {
         WindowKillTimer((CUIWINDOW*) w, MY_TIMER);
      }

      return TRUE;
   }
   return FALSE;
}

void MyTimerHook(void* w, int id)
{
   WindowInvalidate((CUIWINDOW*) w);
}

int main(void)
{
   CUIWINDOW* mywin;

   WindowStart(TRUE, TRUE);
   atexit(quit);

   mywin = WindowNew(WindowGetDesktop(),
                     0, 0, 25, 7,
                     CWS_POPUP | CWS_BORDER | CWS_CENTERED);

   WindowSetText      (mywin, "Clock Window");
   WindowSetPaintHook (mywin, MyPaintHook);
   WindowSetKeyHook   (mywin, MyKeyHook);
   WindowSetTimerHook (mywin, MyTimerHook);

   WindowCreate       (mywin);
   WindowSetTimer     (mywin, MY_TIMER, 500);

   return WindowRun();
}

\end{verbatim}

Zun"achst ist die ''main''-Routine zu beachten. Hier wird wie gehabt der
curses-Modus aktiviert und anschlie"send "uber ''WindowNew'' eine neue
Fensterinstanz angelegt. Diese erh"alt einen Verweis auf das Vaterfenster
(hier das Desktop-Fenster), eine Position (0, 0) und eine Gr"o"se (25, 7).
Zudem werden mehrere Fensterstile angegeben, die festlegen, dass das
Fenster ein Popup-Fenster mit einem Rand sein soll und immer zentriert
in der Bildschirmmitte anzuordnen ist.

Nun wird das Fenster spezialisiert, indem es einen Fenstertitel und drei
Hook-Funktionen zugewiesen bekommt. Die Hook-Funktion ''MyPaintHook''
ist f"ur das Zeichnen des Client-Bereichs des Fensters zust"andig, die
Hook-Funktion ''MyKeyHook'' bearbeitet die Tastatureingaben des Anwenders
und die Funktion ''MyTimerHook'' empf"angt Timer-Ereignisse, falls ein
Window-Timer aktiviert wurde.

Abschlie"send wird das Fenster "uber ''WindowCreate'' erzeugt und erh"alt
zudem durch ''WindowSetTimer'' einen Window-Timer zugewiesen, der alle
500 Millisekunden abl"auft.

Die Funktion ''WindowRun'' aktiviert nun den Window-Manager und kehrt
erst dann zum Hauptprogramm zur"uck, wenn das Fenster geschlossen wurde.
Der R"uckgabewert
ist dabei der Exit-Code, der der WindowClose-Funktion mitgegeben wurde
(siehe ''MyKeyHook'').

Die Hook-Funktion ''MyPaintHook'' ermittelt das Rechteck des Client-Bereichs
des Fensters und zudem die aktuelle Systemzeit. Letztere wird in eine
Zeichenkette umgewandelt und mit der curses-Funktion ''mvwaddstr''
zentriert im Fenster ausgegeben. Dabei ist unbedingt zu beachten, dass
keine curses-Funktion aufgerufen wird, die f"ur die Aktualisierung des
Bildschirminhalts zust"andig ist (''wupdate'' o."a.). Die Aktualisierung wird
vollst"andig vom Fenster-Manager "ubernommen.

Bei der Funktion ''MyKeyHook'' handelt es sich um eine Hook-Funktion, die
einen bool-Wert als R"uckgabewert kennt. "Uber diesen wird dem System
signalisiert, ob das an die Funktion "ubergebene Zeichen behandelt wurde
oder nicht. Falls die Funktion ''FALSE'' zur"uckgibt, wird die Standardbehandlung
der libCUI f"ur die eingegebene Taste aktiv.

Falls die Funktion ''MyKeyHook'' die F10-Taste erkennt, wird versucht
das Fenster "uber die Funktion ''WindowClose'' zu schlie"sen, was im vorliegenden
Fall auch immer gelingt. Im Hintergrund wird dabei die hier nicht implementierte
Hook-Funktion ''CanCloseHook'' f"ur das aktuelle Fenster (und alle seine Kindfenster)
aufgerufen, "uber die angefragt wird, ob das Schlie"sen des Fensters erlaubt ist
oder nicht. Falls das Fenster geschlossen wurde, wird auch der Window-Timer
beendet.

Die Timer-Funktion ''MyTimerHook'' verzichtet auf die Auswertung des Parameters
''id'', da nur ein Timer aktiviert wurde. Anderenfalls muss "uber ''id''
der richtige Timer zugeordnet werden. Der Aufruf der Funktion ''WindowInvalidate''
bewirkt ein Neuzeichnen des Fensters und damit das Aktualisieren des Bildschirminhaltes.
Alternativ h"atten auch direkt hier die Textausgaben in das Fenster erfolgen k"onnen.
Allerdings darf dann am Ende der Funktion der Funktionsaufruf ''WindowInvalidateScreen''
nicht fehlen, der die Bildschirmausgabe (ohne Neuzeichnen des Fensters) erzwingt.





\section{Fensterklassen und Instanzen}

Im Grunde ist die Programmierung unter der libCUI in Ans"atzen mit der
objektorientierten Programmierung vergleichbar. Der vorliegende Abschnitt soll
diese Sichtweise verdeutlichen.

Jedes Fenster ist eine Instanz des Objekts CUIWINDOW, wobei die (virtuellen)
Objektmethoden des Objekts die Hook-Funktionen sind und die Datenelemente
(Objektvariablen) in CUIWINDOW->InstData gespeichert werden. Soll ein Fenster
mit einem Verhalten implementiert werden, das vom Standardverhalten abweicht,
was so gut wie immer der Fall sein sollte, dann erbt das Fenster zun"achst das
Standardverhalten, kann dieses aber durch "uberschreiben der Hook-Funktionen
"andern.

Da jedoch unter 'C' die erforderlichen Sprachelemente fehlen, also keine
Konstruktoren oder Destruktoren verf"ugbar sind und auch kein ''this'' Zeiger
funktioniert, sind ein paar Klimmz"uge bei der Programmierung erforderlich:

\begin{figure}
  \includegraphics[width=6in]{pics/window5.png}
\end{figure}


\subsection{Objekt anlegen}

Instanz anlegen -> WindowNew() \\
Objektmethoden zuweisen -> WindowSetHookXXXX() \\
Datenbereich des Objekts -> win->InstData = malloc(sizeof(MYDATA)); \\
Curses Fenster erzeugen -> WindowCreate() \\

Der Datenbereich des Objekts k"onnte auch im Hook ''WindowCreateHook'' angelegt
werden (den man als Konstruktor verstehen k"onnte).

\subsection{Objekt l"oschen}

Wird WindowDestroy(win) aufgerufen, dann wird das Fenster und alle Kindfenster
gel"oscht. Dabei wird der Hook ''WindowDestroyHook'' aufgerufen.
Der WindowDestroyHook ist quasi der Destruktor der Objektinstanz. Hier m"ussen
alle Datenelemente in win->InstData gel"oscht werden. Im einfachsten Fall ist das:

free(win->InstData);

Das L"oschen der Fensterstruktur selbst (die mit WindowNew angelegt wurde) "ubernimmt der
Window-Manager.

\subsection{Objekt referenzieren}

Da es in 'C' keinen ''this'' Zeiger gibt, ist nicht bekannt, mit welcher Fensterinstanz
ein Hook- Aufruf verbunden ist. Beispielsweise verwenden alle Edit-Controls die
selben Hooks.

Deshalb ist im Hook immer der Parameter ''w'' enthalten, der ein nicht typisierter
Zeiger auf die Fenster-Instanz ist (also sozusagen ''this'').

"uber w->InstData kann dann auf die Objektvariablen der Objektinstanz zugegriffen werden.
Solange nicht sicher ist, dass es nur eine Instanz eines Fensters geben wird, sollte
also nicht mit globalen Veriablen sondern mit Instanzdaten geabreitet werden.

\subsection{Typsicherheit}

Da immer "uber Zeiger vom Typ ''CUIWINDOW'' auf Fensterinstanzen zugegriffen wird, ist
die Typsicherheit gleich null. Wird "uber den InstData-Zeiger auf Datenelemente
zugegriffen, die diese Fensterinstanz nicht kennt, dann sind die Folgen fatal.
So kann z.B. ein CUIWINDOW-Zeiger auf eine ListBox an eine Routine "ubergeben werden,
die ein Edit-Control erwartet. Ohne weitere Ma"snahmen w"urde das Programm mit ziemlicher
Sicherheit abst"urzen.

Aus diesem Grund kennt die CUIWINDOW-Struktur den ''Class''-Zeiger, der auf eine konstante
Zeichenkette zeigt, die den Namen der Klasse enth"alt. Standardm"a"sig zeigt dieser Zeiger immer
auf die Zeichenkette ''WINDOW''. Dies kann jedoch nach dem Anlegen einer Fensterinstanz
ge"andert werden.

Vor dem Zugriff auf ein Datenfeld einer Instanz, sollte deren Klassenzugeh"origkeit gepr"uft
werden. Allerdings gibt es bislang noch keinen Mechanismus innerhalb der libCUI, der
doppelte Klassennamen verhindert.

Beispiel:

\begin{verbatim}

CUIWINDOW*
EditNew(CUIWINDOW* parent, const char* text,
        int x, int y, int w, int h,
        int len, int id, int sflags, int cflags)
{
   if (parent)
   {
      CUIWINDOW* edit;
      int flags = sflags | CWS_TABSTOP;
      flags &= ~(cflags);

      edit = WindowNew(parent, x, y, w, h, flags);
      edit->Class = "EDIT";

      ...

      return edit;
   }
   return NULL;
}


void
EditSetText(CUIWINDOW* win, const char* text)
{
   if (win && (strcmp(win->Class, "EDIT") == 0))
   {
      EDITDATA* data = (EDITDATA*) win->InstData;
      strncpy(data->EditText, text, data->Len);
      data->EditText[data->Len] = 0;

      if (win->IsCreated)
      {
         WindowInvalidate(win);
      }
   }
}

\end{verbatim}

Das Code-Fragment zeigt einen Ausschnitt aus der Implementierung des
Edit- Kontrollelements, das von der libCUI zur Verf"ugung gestellt wird.
Es ist dabei zu sehen, wie in der Funktion ''EditNew'' neue Instanzen
angelegt und mit dem Klassenname ''EDIT'' versehen werden. Beim
sp"ateren Zugriff auf eine Fensterinstanz mittels ''EditSetText'' wird
der Klassenname gepr"uft, bevor auf die Daten des Kontrollelements
zugegriffen wird.


\section{Fensterstile}

Fensterstile werden bei dem Anlegen neuer Fensterinstanzen durch ''WindowNew''
an die Fenster weitergegeben. Die Verkn"upfung der einzelnen Stile erfolgt
dabei mit dem ''Oder''- Operator ''|''.

In der Regel beeinflusst ein Fensterstil eine Flag-Variable innerhalb der
Struktur ''CUIWINDOW''. Der Stil ''CWS\_HIDDEN'' bilded sich so z.B. in dem
Flag ''IsHidden'' ab. Manche der Stile (Flags) k"onnen und d"urfen "uber geeignete API-
Funktionen w"ahrend der Existenz des Fensters ge"andert werden (z.B. WindowShow()),
die "uberigen, f"ur die keine API- Funktionen zur Verf"ugung stehen, sollten
dagegen so beibehalten werden, wie sie von ''WindowNew'' "ubernommen wurden.

Die folgende Tabelle zeigt eine "ubersicht "uber die Fensterstile, die in der libCUI
bisher definiert und mit einer Funktion belegt sind:


\begin{tabularx}{\textwidth}[t]{l|X}
\bf{Stil}& \bf{Bedeutung}\\
\hline
\texttt{ CWS\_NONE}     &   Platzhalter f"ur ''keine Stilangabe''. \\
\texttt{ CWS\_BORDER}   &   Fenster hat einen Rand. \\
\texttt{ CWS\_CAPTION}  &   Fenster hat eine Kopfzeile. \\
\texttt{ CWS\_HIDDEN}   &   Das Fenster ist verborgen. \\
\texttt{ CWS\_DISABLED} &   Das Fenster wird deaktiviert dargestellt und erlaubt keine Tastatureingabe. \\
\texttt{ CWS\_TABSTOP}  &   Das Fenster akzeptiert den Eingabefokus. \\
\texttt{ CWS\_CENTERED} &   Das Fenster wird immer zentriert dargestellt (nur sinnvoll in Kombination mit CWS\_POPUP). \\
\texttt{ CWS\_POPUP}    &   Das Fenster ist ein Popup-Fenster. \\
\texttt{ CWS\_MAXIMIZED} &   Das Fenster ist maximiert und wird in seiner Gr"o"se immer an den Client-Bereich des Vaterfensters
                       (bzw. des Desktop-Fensters) angepasst. \\
\texttt{ CWS\_MINIMIZED} & Das Fenster ist minimiert (im Effekt wie CWS\_HIDDEN). \\
\texttt{ CWS\_STATUSBAR} & Das Fenster hat eine Statuszeile. \\
\texttt{ CWS\_DEFOK}     & Das Fenster ist das Standard-Kontrollelement der ENTER-Taste. Falls ENTER nicht mit
               einer speziellen Funktion belegt ist, wird das Kindfenster mit dem Stil CWS\_DEFOK gesucht.
               Handelt es sich dabei um eine Schaltfl"ache, dann wird diese bet"atigt. \\
\texttt{ CWS\_DEFCANCEL} & Wie CWS\_DEFOK, nur dass hier die ESCAPE-Taste mit dem Kontrollelement verbunden ist. \\
\end{tabularx}

~\\
Die Flags ''CWS\_MAXIMIZED'', ''CWS\_MINIMIZED'', ''CWS\_HIDDEN'' und auch ''CWS\_- DISABLED'' k"onnen mit den
folgenden API-Funktionen w"ahrend der Existenz des Fensters beeinflusst werden:

\begin{verbatim}

int  WindowMaximize(CUIWINDOW* win, int state);
int  WindowMinimize(CUIWINDOW* win, int state);
void WindowHide(CUIWINDOW* win, int state);
void WindowEnable(CUIWINDOW* win, int state);
\end{verbatim}


\section{Hook-Funktionen}

    Wie bereits in den vorhergehenden Abschnitten mehrfach angedeutet, wird das
    Verhalten eines Fensters von den Hook-Funktionen bestimmt. Hook-Funktionen
    werden vom Fenster- Manager aufgerufen, wenn ein Ereignis an ein Fenster
    gesendet werden soll. Ist dabei eine Hookfunktion nicht zugewiesen, dann
    tritt die jeweilige Standard-Behandlung in Kraft.

    Die folgenden Funktionen werden verwendet um einem Fenster Hook-Funktionen
    zuzuweisen:

\begin{verbatim}

void WindowSetCreateHook(CUIWINDOW* win, HookProc proc);
void WindowSetInitHook(CUIWINDOW* win, HookProc proc);
void WindowSetCanCloseHook(CUIWINDOW* win, BoolHookProc proc);
void WindowSetDestroyHook(CUIWINDOW* win, HookProc proc);

void WindowSetPaintHook(CUIWINDOW* win, HookProc proc);
void WindowSetNcPaintHook(CUIWINDOW* win, Hook2IntProc proc);
void WindowSetSizeHook(CUIWINDOW* win, BoolHookProc proc);
void WindowSetSetFocusHook(CUIWINDOW* win, Hook1PtrProc proc);
void WindowSetKillFocusHook(CUIWINDOW* win, HookProc proc);

void WindowSetKeyHook(CUIWINDOW* win, BoolHook1IntProc proc);

void WindowSetMMoveHook(CUIWINDOW* win, Hook2IntProc proc);
void WindowSetMButtonHook(CUIWINDOW* win, Hook3IntProc proc);
void WindowSetVScrollHook(CUIWINDOW* win, Hook2IntProc proc);
void WindowSetHScrollHook(CUIWINDOW* win, Hook2IntProc proc);

void WindowSetTimerHook(CUIWINDOW* win, Hook1IntProc proc);
\end{verbatim}

    \subsection {CreateHook}
    Prototyp:
    \begin{verbatim}
        void CreateHook(void* win);
    \end{verbatim}

    Der Create-Hook wird immer unmittelbar nach dem Erzeugen eines
    Fensters (innerhalb von ''WindowCreate'') aufgerufen. Es ist die
    erste Hook-Funktion die im Laufe eines Lebenszyklus eines Fensters
    aufgerufen wird.

    Der Create-Hook kann verwendet werden, um die Instanz-Daten
    anzulegen oder um Kindfenster zu erzeugen.

    \subsection {InitHook}
    Prototyp:
    \begin{verbatim}
        void InitHook(void* win);
    \end{verbatim}

    Der Init-Hook wird ebenfalls aus der Funktion ''WindowCreate'' heraus
    aufgerufen. Allerdings nachdem der CreateHook ausgef"uhrt und
    das Fenster "uber den PaintHook (und den NcPaintHook) zum Neuzeichnen
    aufgefordert wurde.

    Der Init-Hook kann verwendet werden, um z.B. einen Anmeldedialog
    oder "Ahnliches darzustellen, der als Popup-Fenster "uber dem
    gerade erzeugten Fenster erscheinen soll.

    \subsection {CanCloseHook}
    Prototyp:
    \begin{verbatim}
        int CanCloseHook(void* win);
    \end{verbatim}

    Soll ein Fenster "uber die API-Funktion ''WindowClose'' geschlossen
    werden, dann fragt der Fenster- Manager das betroffene Fenster und
    alle seine Kindfenster an, ob ein Schlie"sen m"oglich ist. Die Hook-
    Funktion soll dabei den Wert ''TRUE'' zur"uckliefern, wenn das
    Fenster geschlossen werden kann und ''FALSE'' falls nicht.
    Als Standard f"ur diese Hook-Funktion wird ein R"uckgabewert von
    ''TRUE'' angenommen.

    Der CanClose-Hook kann u.a. verwendet werden, um z.B. das Schlie"sen
    eines Fensters zu verhindern, solange nicht alle Daten gespeichert
    wurden.

    \subsection {DestroyHook}
    Prototyp:
    \begin{verbatim}
        void DestroyHook(void* win);}
    \end{verbatim}

    Der Destroy-Hook wird aufgerufen, bevor ein Fenster endg"ultig aus
    dem Fensterstapel entfernt wird. Es ist die letzt Hook-Funktion,
    die ein Fenster im Laufe seiner Existenz sieht.

	Hier werden "ublicherweise die Instanz-Daten freigegeben, die mit
	dem Fenster verbunden sind. Kindfenster oder die CUIWINDOW- Struktur
	selbst brauchen und d"urfen jedoch nicht freigegeben werden. Daf"ur
	sorgt das Fenstersystem selbst.

    \subsection {PaintHook}
    Prototyp:
    \begin{verbatim}
        void PaintHook(void* win);
    \end{verbatim}

    Der Paint-Hook fordert das Fenster zum Neuzeichnen des Client-
    Bereichs auf. Dies geschieht immer dann, wenn das Fenster
    erzeugt wurde, wenn sich die Gr"o"se des Fensters ver"andert hat
    oder wenn das Fenster manuell "uber ''WindowInvalidate'' als
    ung"ultig erkl"art wurde.

    Zur Textausgabe werden die bekannten curses-Funktionen wie
    ''waddstr'' o."a. verwendet, wobei das zugeh"orige curses-Fenster
    "uber das CUIWINDOW-Datenelement ''Win'' angesprochen wird!

    \subsection {NcPaintHook}
    Prototyp:
    \begin{verbatim}
        void NcPaintHook(void* win, size x, size y);
    \end{verbatim}

    Der NcPaint-Hook fordert das Fenster zum Neuzeichnen des Nicht-
    Client Bereichs (= Fensterrahmen, Titel, Bildlaufleisten etc.) auf.
    Dies geschieht immer dann, wenn das Fenster
    erzeugt wurde, wenn sich die Gr"o"se des Fensters ver"andert hat
    oder wenn das Fenster manuell "uber ''WindowInvalidate'' als
    ung"ultig erkl"art wurde.

    Achtung: Die libCUI implementiert bereits ein Standardverhalten
    zum Zeichnen des Nicht-Client Bereichs. Diese Hook-Funktion braucht
    deshalb nur dann implementiert werden, wenn das Standardverhalten nicht
    ausreicht.

    Zur Textausgabe werden die bekannten curses-Funktionen wie
    ''waddstr'' o."a. verwendet, wobei das zugeh"orige curses-Fenster
    "uber das CUIWINDOW-Datenelement ''Frame'' angesprochen wird!

    \subsection {SizeHook}
    Prototyp:
    \begin{verbatim}
        int SizeHook(void* win);
    \end{verbatim}

    Der Size-Hook wird aufgerufen, wenn sich die Gr"o"se eines Fensters
    ver"andert hat. Falls die Darstellung des Fensters oder die
    Ausrichtung der Kindfenster von dieser Gr"o"sen"anderung betroffen sind,
    kann dies bei Bedarf innerhalb dieses Hooks angepasst werden.

    Achtung: Die libCUI implementiert bereits ein Standardverhalten
    f"ur die Gr"o"sen"anderung. Dabei werden alle maximierten Kindfenster
    auf die Gr"o"se des Client-Bereichs angepasst. Falls diese
    Funktionalit"at nicht erw"unscht ist, sollte die Funktion ''TRUE''
    zur"uckgeben und damit dem Fenster-Manager signalisieren, dass sie
    die Gr"o"sen"anderung vollst"andig selbst "ubernommen hat.

    \subsection {SetFocusHook}
    Prototyp:
    \begin{verbatim}
        void SetFocusHook(void* win, void* lastfocus);
    \end{verbatim}

    Wird aufgerufen, wenn ein Fenster den Eingabefokus erh"alt.
    Der Parameter ''lastfocus'' enth"alt dabei eine Referenz auf das
    Fenster, das zuletzt im Besitz des Eingabefokus war.

    Diese Funktion wird oftmals dazu verwendet, um die Sichtbarkeit
    des Cursors zu steuern.

    \subsection {KillFocusHook}
    Prototyp:
    \begin{verbatim}
        void KillFocusHook(void* win);
    \end{verbatim}

    Wird aufgerufen, wenn einem Fenster der Eingabefokus entzogen
    wird.

    Diese Funktion wird oftmals dazu verwendet, um die Sichtbarkeit
    des Cursors zu steuern.

    \subsection {KeyHook}
    Prototyp:
    \begin{verbatim}
        int KeyHook(void* win, int key);
    \end{verbatim}

    Wird immer dann aufgerufen, wenn ein "uber die Tastatur eingegebenes
    Zeichen an das Fenster mit dem Eingabefokus gesendet werden soll.
    Das Fenster kann dann entspechend auf die Taste reagieren und mit dem
    R"uckgabewert ''TRUE'' signalisieren, dass die Taste akzeptiert wurde.
    Wird statt dessen ''FALSE'' zur"uckgegeben, wird das Standardverhalten
    der libCUI aktiv.

    Das Standardverhalten steuert die Weitergabe des Eingabefokus mit den
    Pfeiltasten oder der TAB- Taste, sowie die Standardbehandlung der ENTER-
    und der ESCAPE- Taste.

    \subsection {MMoveHook}
    Prototyp:
    \begin{verbatim}
        void MMoveHook(void* win, int x, int y);
    \end{verbatim}

    Wird aufgerufen, wenn sich der Mauscursor "uber dem Fenster bewegt.
    Dies funktioniert nur dann, wenn die Mausbehandlung beim Aufruf von
    ''WindowStart'' aktiviert wurde und das Terminal diese Funktion
    unterst"utzt.

    \subsection {MButtonHook}
    Prototyp:
    \begin{verbatim}
        void MButtonHook(void* win, int x, int y, int flags);
    \end{verbatim}

    Wird aufgerufen, wenn eine Maustaste "uber einem Fenster bet"atigt
    wurde. Der Parameter ''flags'' gibt dabei den von curses definierten
    Code f"ur die jeweilige Aktion der Maustasten weiter.

    Dies funktioniert nur dann, wenn die Mausbehandlung beim Aufruf von
    ''WindowStart'' aktiviert wurde und das Terminal diese Funktion
    unterst"utzt.

    \begin{tabularx}{\textwidth}[t]{l|X}
    \bf{flags}& \bf{Bedeutung}\\
    \hline
    \texttt{ BUTTONx\_PRESSED}      &   Maustaste x gedr"uckt\\
    \texttt{ BUTTONx\_RELEASED}     &   Maustaste x losgelassen\\
    \texttt{ BUTTONx\_CLICKED}      &   Maustaste x kurzer Klick\\
    \texttt{ BUTTONx\_DOUBLE\_CLICKED} &   Maustaste x Doppelklick\\
    \texttt{ BUTTONx\_TRIPLE\_CLICKED} &   Maustaste x Dreifachklick\\
    \end{tabularx}

    ~\\
    In obenstehender Tabelle ist x ein Platzhalter f"ur Werte zwischen 1 und 4.


    \subsection {VScrollHook}
    Prototyp:
    \begin{verbatim}
        void VScrollHook(void* win, int sbcode, int pos);
    \end{verbatim}

    Wird aufgerufen, wenn die vertikale Bildlaufleiste eines Fensters
    mit der Maus bet"atigt wurde. Dabei wird im Parameter ''sbcode''
    die Art der Bet"atigung weitergegeben:

    \begin{tabularx}{\textwidth}[t]{l|X}
    \bf{sbcode}& \bf{Bedeutung}\\
    \hline
    \texttt{ SB\_LINEDOWN}   &   Zeilenweise nach unten scrollen\\
    \texttt{ SB\_LINEUP}     &   Zeilenweise noch oben scrollen \\
    \texttt{ SB\_PAGEDOWN}   &   Seitenweise nach unten scrollen \\
    \texttt{ SB\_PAGEUP}     &   Seitenweise nach oben scrollen \\
    \texttt{ SB\_THUMBTRACK} &   Direktes Verschieben auf die Position ''pos'' \\
    \end{tabularx}

	~\\
    Der Parameter ''pos'' hat nur dann einen sinnvollen Wert, wenn ''sbcode''
    den Wert ''SB\_- THUMBTRACK'' enth"alt.


    \subsection {HScrollHook}
    Prototyp:
    \begin{verbatim}
        void HScrollHook(void* win, int sbcode, int pos);
    \end{verbatim}

    Wird aufgerufen, wenn die horizontale Bildlaufleiste eines Fensters
    mit der Maus bet"atigt wurde. Dabei wird im Parameter ''sbcode''
    die Art der Bet"atigung weitergegeben:

    \begin{tabularx}{\textwidth}[t]{l|X}
    \bf{sbcode}& \bf{Bedeutung}\\
    \hline
    \texttt{ SB\_LINEDOWN}   &   Spaltenweise nach rechts scrollen\\
    \texttt{ SB\_LINEUP}     &   Spaltenweise noch links scrollen \\
    \texttt{ SB\_PAGEDOWN}   &   Seitenweise nach rechts scrollen \\
    \texttt{ SB\_PAGEUP}     &   Seitenweise nach links scrollen \\
    \texttt{ SB\_THUMBTRACK} &   Direktes Verschieben auf die Position ''pos'' \\
    \end{tabularx}

	~\\
    Der Parameter ''pos'' hat nur dann einen sinnvollen Wert, wenn ''sbcode''
    den Wert ''SB\_- THUMBTRACK'' enth"alt.


    \subsection {TimerHook}
    Prototyp:
    \begin{verbatim}
        void TimerHook(void* win, int id);
    \end{verbatim}

    Wird aufgerufen, wenn ein f"ur dieses Fenster aktivierter Window- Timer
    abgelaufen ist. "Uber den Parameter ''id'' kann dabei der jeweilige
    Timer identifiziert werden.


    \section {Darstellung und Bildschirm-Update}

    Wie die curses-Bibliothek, versucht auch die libCUI die
    Bildschirmausgaben so zu optimieren, dass m"oglichst wenige Daten
    an das Terminal gesendet werden m"ussen. Deshalb erscheint die
    Darstellung von Textausgaben in einem Fenster nicht unmittelbar
    am Bildschirm, sondern nur unter bestimmten Umst"anden:

    Paint-Hook\\
    Wird die Textausgabe innerhalb einer Paint- oder NcPaint-
    Ereignisbehandlung durchgef"uhrt, dann wird anschlie"send der
    Bildschirminhalt automatisch als ung"ultig erkl"art. Dies
    wiederum bewirkt automatisch die Aktualisierung des Terminals.
    Es handelt sich hierbei um den empfohlenen Standardfall. Soll
    aufgrund einer Status"anderung der Fensterinhalt ver"andert werden,
    kann der Aufruf der Paint-Routine "uber die Funktion ''WindowInvalidate()''
    jederzeit erzwungen werden.

    Direkte Textausgabe\\
    Falls jedoch eine direkte Textausgabe in ein Fenster au"serhalb der
    Paint-Routine erforderlich ist, muss anschlie"send der Bildschirminhalt
    manuell als ung"ultig erkl"art werden. Dies geschieht mit der API-Funktion
    ''WindowInvalidateScreen()''. Der Fenster-Manager wird daraufhin die
    Aktualisierung des Bildschirminhaltes an geeigneter Stelle vornehmen.

    Erzwungenes Bildschirmupdate\\
    Muss zu einem definierten Zeitpunkt ein Bildschirmupdate unbedingt
    sein, dann kann dies mittels der Funktion ''WindowUpdate()'' ausgef"uhrt
    werden. Allerdings ist zu beachten, dass aus Performance-Sicht
    erzwungene Bildschirmupdates die schlechteste L"osung sind.

    \section {Tastatureingabe und Eingabefokus}

    Tastatureingaben werden immer an dasjenige Fenster weitergeleitet, das
    gegenw"artig den Eingabefokus besitzt. Ist f"ur dieses Fenster keine
    KeyHook- Funktion angemeldet oder gibt diese den R"uckgabewert ''FALSE''
    zur"uck, wird das Standardverhalten der libCUI aktiv.

    Das Standardverhalten l"auft dabei nach folgendem Schema ab:

    {\it Pfeil- und Tab-Tasten:} \\
    Der Eingabefokus wird an das n"achste (bzw. je nach Taste an das vorherige)
    Kindfenster weitergeleitet, das sichtbar und aktiv ist und zudem den Fokus
    akzeptiert (CWS\_TABSTOP).

    Wird das Ende der Fensterliste der Kindfenster erreicht (oder existieren keine
    Kindfenster im aktuellen Fenster), dann wird die Aufgabe der Fokusweitergabe an
    das Vaterfenster delegiert. Dies geschieht jedoch nur, solange es
    sich beim aktuellen Fenster nicht um ein Popup-Fenster handelt.

    Im Gegensatz zu normalen Fenstern beginnen Popup-Fenster beim Erreichen des
    Listenendes die Fokusweitergabe
    wieder am anderen Ende ihrer Fensterliste. Dadurch bildet die Weiterleitung
    des Fokus auf der Ebene des Popup-Fensters einen geschlossenen Kreis.

    {\it ENTER- und ESC- Tasten:} \\
    Es wird dasjenige Kindfenster gesucht, das den Fensterstil CWS\_DEFOK (bzw.
    CWS\_DEF- CANCEL) besitzt. Wird ein solches Fenster gefunden und handelt es
    sich dabei um ein Button- Konrollelement, dann wird dieses bet"atigt.

    {\it Alphanumerische Tasten:} \\
    Es wird dasjenige Kindfenster gesucht, das das eingegebene Zeichen als
    Hot-Key hinterlegt hat. Falls ein solches Fenster gefunden wird, wird ihm
    der Eingabefokus zugewiesen und zugleich das fragliche Zeichen "ubergeben.
    Anderenfalls wird die Tastatureingabe verworfen.

    Nat"urlich kann die Fokusweitergabe auch manuell im Programmcode beeinflusst
    werden. Es existieren dazu die folgenden Funktionen:

\begin{verbatim}
   void WindowSetFocus(CUIWINDOW* win);
   CUIWINDOW* WindowGetFocus(void);
   void WindowFocusNext(CUIWINDOW* win);
   void WindowFocusPrevious(CUIWINDOW* win);
\end{verbatim}

    \section {Window-Timer}

    Soll ein sich zeitlich wiederholender Ablauf programmiert werden, dann kann
    dazu ein Window-Timer verwendet werden. Ein Window-Timer hat eine Aufl"osung
    von 100ms, besitzt aber keinen Anspruch auf Genauigkeit.

    Um mit einem Timer zu Arbeiten, muss zun"achst ein TimerHook f"ur das
    entsprechende Fenster angemeldet werden. Dann wird der Timer mit der
    Funktion ''WindowSetTimer'' gestartet. Die Funktion ''WindowKillTimer''
    deaktiviert den Timer wieder.

\begin{verbatim}
   void WindowSetTimer(CUIWINDOW* win, int id, int msec);
   void WindowKillTimer(CUIWINDOW* win, int id);
\end{verbatim}

    \section {Farben}

    Wenn beim Funktionsaufruf ''WindowStart'' der Farbmodus aktiviert wurde und
    zudem die aktuelle Konsole Farben unterst"utzt, dann k"onnen w"ahrend der
    Textausgabe in ein Fenster die Vorder- und die Hintergrundfarbe mit der
    Funktion ''SetColor'' gesetzt werden. Dazu existieren die folgenden
    Farbkonstanten (die den curses-Konstanten COLOR\_XXXX entsprechen):

    \begin{tabularx}{\textwidth}[t]{X|X|X|X}
    \bf{Konstante}& \bf{Wert} & \bf{Konstante} & \bf{Wert}\\
    \hline
    \texttt{ BLACK} & 0 & \texttt{ DARKGRAY} & 8\\
    \texttt{ BLACK} & 1 & \texttt{ LIGHTRED} & 9\\
    \texttt{ GREEN} & 2 & \texttt{ LIGHTGREEN} & 10\\
    \texttt{ BROWN} & 3 & \texttt{ YELLOW} & 11\\
    \texttt{ BLUE}  & 4 & \texttt{ LIGHTBLUE} & 12\\
    \texttt{ MAGENTA}   & 5 & \texttt{ LIGHTMAGENTA} & 13\\
    \texttt{ CYAN}      & 6 & \texttt{ LIGHTCYAN} & 14\\
    \texttt{ LIGHTGRAY} & 7 & \texttt{ WHITE} & 15\\
    \end{tabularx}

    Die Funktion ''SetColor'' kennt vier Parameter. Dies sind das curses-
    Fenster auf das die Farb"anderung angewendet werden soll, die Vordergrundfarbe
    und die Hintergrundfarbe. Der letzte Parameter gibt an, ob die Darstellung
    im monochromen Modus invers sein soll.

\begin{verbatim}
   void SetColor(WINDOW* win, int fcolor, int bcolor, int reverse);
\end{verbatim}

    Allerdings kann es durchaus sinnvoll sein, die Farbkonstanten nicht
    direkt zu verwenden, sondern mit den Farben zu arbeiten, die dem Fenster
    hinterlegt sind. Dazu existiert innerhalb der CUIWINDOW- Struktur ein
    Datenelement ''Color'', das ebenfalls eine Struktur mit den folgenden
    Datenfeldern ist:

    \begin{tabularx}{\textwidth}[t]{l|l|X}
    \bf{Datenfeld}& \bf{Typ} & \bf{Bedeutung}\\
    \hline
    \texttt{ WndColor} & int & \texttt{ normal window background color}\\
    \texttt{ WndSelColor} & int & \texttt{ selected text background color}\\
    \texttt{ WndTxtColor} & int & \texttt{ normal window text color}\\
    \texttt{ SelTxtColor} & int & \texttt{ selected text color}\\
    \texttt{ InactTxtColor}  & int & \texttt{ inactive window text color}\\
    \texttt{ HilightColor}   & int & \texttt{ hilight window text color }\\
    \texttt{ TitleTxtColor}  & int & \texttt{ window caption text color}\\
    \texttt{ TitleBkgndColor} & int & \texttt{ window caption background color}\\
    \texttt{ StatusTxtColor}  & int & \texttt{ window status bar text color}\\
    \texttt{ StatusBkgndColor} & int & \texttt{ window status bar bkgnd color}\\
    \end{tabularx}

    ~\\
    Ein Code-Schnipsel aus einer Paint-Routine kann dann wie folgt aussehen:

\begin{verbatim}
   if (index == data->SelIndex)
   {
      SetColor(win->Win, win->Color.SelTxtColor,
               win->Color.WndSelColor, TRUE);
      cursor = y;
   }
   else
   {
      if (win->IsEnabled)
      {
         SetColor(win->Win, win->Color.WndTxtColor,
                  win->Color.WndColor, FALSE);
      }
      else
      {
         SetColor(win->Win, win->Color.InactTxtColor,
                  win->Color.WndColor, FALSE);
      }
   }
   for (x = 0; x < rc.W; x++)
   {
      if ((x > 0) && (x <= len))
      {
         wprintw(win->Win, "%c", item->ItemText[x - 1]);
      }
      else if (x == 0)
      {
         mvwprintw(win->Win, y, 0, " ");
      }
      else
      {
         wprintw(win->Win, " ");
      }
   }
\end{verbatim}

    Beim Anlegen einer Fensterstruktur erbt das neue Fenster seine Farben von seinem
    Vaterfenster. Es kann jedoch "uber die Funktion ''WindowColScheme'' ein abweichendes
    Farbschema zugewiesen werden. Farbschemata haben Namen und werden "uber die Funktion
    ''WindowAddColScheme'' hinzugef"ugt bzw. ge"andert. Standardm"a"sig sind die Schemata
    ''WINDOW'', ''DESKTOP'', ''DIALOG'', ''MENU'', ''TERMINAL'' und ''HELP'' definiert.

    Die Funktionen im "uberblick:

\begin{verbatim}
   void WindowAddColScheme(const char* name, CUIWINCOLOR* colrec);
   int  WindowHasColScheme(const char* name);
   void WindowColScheme(CUIWINDOW* win, const char* name);
\end{verbatim}

    Ein Beispiel:

\begin{verbatim}
   CUIWINDOW* mynewwin;
   CUIWINCOLOR* colrec;

   colrec.WndColor = BLUE;
   colrec.WndSelColor = LIGHTGRAY;
   colrec.WndTxtColor = LIGHTGRAY;
   colrec.SelTxtColor = BLACK;
   colrec.InactTxtColor = DARKGRAY;
   colrec.HilightColor = YELLOW;
   colrec.TitleTxtColor = BLACK;
   colrec.TitleBkgndColor = LIGHTGRAY;
   colrec.StatusTxtColor = BLACK;
   colrec.StatusBkgndColor = LIGHTGRAY;
   WindowAddColScheme("MY_SCHEME", &colrec);

   mynewwin = WindowNew(aparent, 0, 0, 10, 10, CWS_NONE);
   WindowColScheme(mynewwin, "MY_SCHEME");
   WindowCreate(mynewwin);
   ...
\end{verbatim}


    \section {Bildlaufleisten}

    Ein Fenster kann eine vertikale und eine horizontale Bildlaufleiste (Scrollbalken)
    besitzen. Bildlaufleisten werden verwendet, um dem Anwender zu zeigen, an welcher
    Stelle innerhalb eines Bereiches (z.B. innerhalb einer Liste oder eines Textes)
    er sich befindet.

    Ist ein Fenster mit der Eigenschaft CWS\_BORDER versehen, dann finden die
    Bildlaufleisten auf dem Fensterrahmen Platz. Anderenfalls erfolgt die
    Darstellung der Scrollbalken am rechten bzw. unteren Fensterrand. Der Client-Bereich
    des Fensters wird dabei entsprechend verkleinert.

    Mit den folgenden Funktionen werden Bildlaufleisten gesetzt und abgefragt:

\begin{verbatim}
   void WindowEnableVScroll(CUIWINDOW* win, int enable);
   void WindowEnableHScroll(CUIWINDOW* win, int enable);
   void WindowSetVScrollRange(CUIWINDOW* win, int range);
   void WindowSetHScrollRange(CUIWINDOW* win, int range);
   void WindowSetVScrollPos(CUIWINDOW* win, int pos);
   void WindowSetHScrollPos(CUIWINDOW* win, int pos);
   int  WindowGetVScrollRange(CUIWINDOW* win);
   int  WindowGetHScrollRange(CUIWINDOW* win);
   int  WindowGetVScrollPos(CUIWINDOW* win);
   int  WindowGetHScrollPos(CUIWINDOW* win);
\end{verbatim}

    Mittels ''WindowEnableVScroll'' bzw. ''WindowEnableHScroll'' wird die
    Sichtbarkeit gesteuert. Hat der Parameter ''enable'' den Wert ''TRUE''
    dann wird die jeweilige Bildlaufleiste angezeigt, anderenfalls nicht.

    Die Funktionen ''WindowSetVScrollRange'' bzw. ''WindowSetHScrollRange''
    geben einer Bildlaufleiste den Scrollbereich vor, wobei der Wert des
    Parameters ''range'' der Maximalwert ist, den die Position der
    Bildlaufleiste annehmen kann. Wird z.B. als Bereich der Wert '1'
    "ubergeben, dann kann die Position die Werte '0' und '1' annehmen.

    Mit ''WindowSetVScrollPos'' bzw. ''WindowSetHScrollPos'' wird die
    Position innerhalb des Scrollbereichs gesetzt.

    Mit den entsprechenden ''Get'' Funktionen k"onnen die aktuellen
    Parameter der Bildlaufleiste abgefragt werden.

    Ist die Mausbehandlung aktiv, dann k"onnen Bildlaufleisten auch mit
    der Maus bedient werden. Die Benachrichtgung an ein Fenster erfolgt
    dabei "uber den ''VScroll''- Hook bzw. "Uber den ''HScroll''- Hook des
    Fensters. Eine
    g"angige Implementierung einer solchen Hook- Funktion sieht wie folgt aus:

\begin{verbatim}
   static void
   ListboxVScrollHook(void* w, int sbcode, int pos)
   {
      CUIWINDOW* win = (CUIWINDOW*) w;
      CUIRECT rc;
      int sbpos, range;

      WindowGetClientRect(win, &rc);
      sbpos = WindowGetVScrollPos(win);
      range = WindowGetVScrollRange(win);

      switch(sbcode)
      {
      case SB_LINEUP:
         if (sbpos > 0)
         {
            WindowSetVScrollPos(win, sbpos - 1);
            WindowInvalidate(win);
         }
         break;
      case SB_LINEDOWN:
         if (sbpos < range)
         {
            WindowSetVScrollPos(win, sbpos + 1);
            WindowInvalidate(win);
         }
         break;
      case SB_PAGEUP:
         if (sbpos > 0)
         {
            sbpos -= (rc.H - 1);
            sbpos = (sbpos < 0) ? 0 : sbpos;
            WindowSetVScrollPos(win, sbpos);
            WindowInvalidate(win);
         }
         break;
      case SB_PAGEDOWN:
         if (sbpos < range)
         {
            sbpos += (rc.H - 1);
            sbpos = (sbpos > range) ? range : sbpos;
            WindowSetVScrollPos(win, sbpos);
            WindowInvalidate(win);
         }
         break;
      case SB_THUMBTRACK:
         WindowInvalidate(win);
         break;
      }
   }
\end{verbatim}

    \section {Mausbehandlung}

    Die Behandlung der Maus wird in der libCUI "uber die Funktion ''WindowStart'' aktiviert.
    Von da ab erh"alt ein Fenster, abh"angig von den M"oglichkeiten die das verwendete
    Terminal bietet, Informationen "uber die Mausbewegung und "uber Aktivit"aten der
    Maustasten. Dazu dienen die beiden Hook- Funktionen ''MMoveHook'' und ''MButtonHook''.

    Die Mausereignisse werden immer an dasjenige Fenster gesendet, "uber dessen Client-
    Bereich sich der Maus-Cursor befindet. Allerdings kann ein Fenster die Maus ''einfangen''
    indem die Funktion ''WindowSetCapture'' aufgerufen wird. Es werden von da an alle
    Ereignisse an das Fenster mit dem Maus- Capture gesendet, bis die Funktion
    ''WindowReleaseCapture'' aufgerufen wird.

    Wird eine Maustaste "uber einem Fenster
    bet"atigt, erh"alt dieses den Eingabefokus zugeteilt. Popup-Fenster werden zudem
    in den Vordergrund gestellt.

    Die Behandlung von Mausereignissen im Randbereich (Nicht- Client Bereich) von Fenstern
    wird von der libCUI selbst verwaltet. Sollte das Standardverhalten nicht gew"unscht
    sein, dann kann ein Fenster "uber die Hook-Funktionen ''MMoveHookNc'' und ''MButtonHookNc''
    eine eigene Implementierung Anstelle der der libCUI einsetzen.
