📄 xmcombo.c
字号:
XtConfigureWidget(w->combobox.LabelCtrl,
0, 0,
LabelCtrlWidth, ComboBoxHeight,
BorderWidth);
}
/* Falls da noch die Liste herumgurkt... */
if ( w->combobox.StaticList ) {
Dimension Width, Height;
if ( w->core.height > ComboBoxHeight )
Height = w->core.height - ComboBoxHeight;
else
Height = 10;
if ( w->core.width > (Dimension)(ArrowCtrlWidth + EditX) )
Width = w->core.width - ArrowCtrlWidth - EditX;
else
Width = 10;
XtConfigureWidget(XtParent(w->combobox.ListCtrl),
EditX + ArrowCtrlWidth, ComboBoxHeight, Width, Height, 0);
} else if ( w->combobox.ListVisible )
DoDropDownLayout(w);
} /* DoLayout */
/* --------------------------------------------------------------------
* Pappi fragt nach, wie gross wir denn sein wollen.
* Die hier benutzte Vorgehensweise zur Ermittlung der Groesse:
* Sobald der Vater uns eine Breite (oder aber Hoehe) vorschlaegt,
* die fuer uns eigentlich zu klein ist, meckern wir und schlagen
* die von uns benoetigte Breite (Hoehe) vor.
* Soweit also zur Theorie... leider sieht es beispielsweise das
* Motif Form-Widget ueberhaupt nicht ein, uns auch nur ein einziges
* Mal nach unseren Wuenschen zu fragen! Damit es bei derart unum-
* gaenglichen Widgets dann doch noch geht, muss ChangedManaged die
* Kohlen wieder aus dem Feuer holen mit einer Sondertour.
* Parameter:
* *Request Vom Vater vorgeschlagene Geometrie
* Ergebnis:
* *Reply Unsere Antwort auf die vorgeschlagene Geometrie
* sowie XtGeometryYes oder XtGeometryAlmost, je nachdem, wie gut
* uns Pappis Vorschlag in den Kram passt.
*/
static XtGeometryResult QueryGeometry(XmComboBoxWidget w,
XtWidgetGeometry *Request,
XtWidgetGeometry *Reply)
{
XtGeometryResult result = XtGeometryYes;
Dimension minW, minH, editW, labelW;
/* Elternteil will nichts weiter aendern, also ist uns das
* recht so.
*/
Request->request_mode &= CWWidth | CWHeight;
if ( Request->request_mode == 0 ) return result;
DefaultGeometry(w, &minW, &minH, &editW, &labelW);
/* Ueberpruefe, ob uns das in der Breite passt, was Pappi moechte... */
if ( Request->request_mode & CWWidth ) {
if ( Request->width < minW ) {
/* Wenn Pappi uns etwas vorschlaegt, was im wahrsten Sinne des Wortes
* vorn und hinten nicht reicht, dann versuchen wir ihn entsprechend
* zu korrigieren. ("Versuchen" deshalb, weil er diesen Vorschlag auch
* voellig ignorieren kann.)
*/
result = XtGeometryAlmost;
Reply->width = minW;
Reply->request_mode |= CWWidth;
}
}
/* Die ganze Chose nun noch vertikal */
if ( Request->request_mode & CWHeight ) {
if ( Request->height < minH ) {
result = XtGeometryAlmost;
Reply->height = minH;
Reply->request_mode |= CWHeight;
}
}
return result;
} /* QueryGeometry */
/* --------------------------------------------------------------------
* Die Groesse des ComboBox-Widgets hat sich veraendert und deshalb
* mussen alle Kinder neu positioniert werden.
* Letzten Endes laeuft hier alles auf ein ordinaeres DoLayout()
* hinaus, um die Kinder umher zu schieben.
* Parameter:
* w Die bereits hinlaenglich bekannte Instanz dieses
* Widgets
*/
static void Resize(XmComboBoxWidget w)
{
DoLayout(w);
} /* Resize */
/* --------------------------------------------------------------------
* Dieses Widget hat sich in irgendeiner Form bewegt (und das nicht
* nur relativ zum Vater, sondern moeglicherweise auch der Vater
* selbst!) bzw. die Shell, in der sich irgendwo unsere Combo-Box
* befindet, hat soeben den Fokus verschusselt und kann ihn nicht
* mehr wiederfinden. Daneben kann es auch sein, dass die Shell
* ikonisiert wurde. (Welch' Vielfalt! Dieses ist hier halt eine
* multifunktionale Routine.)
*
* Parameter:
* w Die naechste Shell in Reichweite ueber unserer
* Combo-Box.
* cbw Diese Combo-Box.
* event ^ auf den Event, enthaelt genauerere Informationen
* (naja... sieht so aus, als ob Motif hier auch
* schon 'mal Schrott 'reinpackt...)
* ContDispatch Auf True setzen, damit dieser Event noch weiter-
* gereicht wird an all' die anderen, die auch noch
* mithoeren.
*/
static void ShellCallback(Widget w, XtPointer pClientData,
XEvent *event, Boolean *ContDispatch)
{
XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData;
switch ( event->type ) {
case ConfigureNotify:
case CirculateNotify:
DoDropDownLayout((XmComboBoxWidget) cbw);
break;
case FocusOut:
LOG3("ShellCallback: FocusOut, mode: %i, detail: %i\n",
(int)event->xfocus.mode, (int)event->xfocus.detail);
if ( cbw->combobox.Persistent )
cbw->combobox.IgnoreFocusOut = True;
else if ( (event->xfocus.mode == NotifyGrab) &&
cbw->combobox.ListVisible )
cbw->combobox.IgnoreFocusOut = True;
break;
case UnmapNotify:
ShowHideDropDownList((XmComboBoxWidget) cbw,
event, False);
break;
}
*ContDispatch = True;
} /* ShellCallback */
/* --------------------------------------------------------------------
* Diese Routine sorgt dafuer, dass die Liste nicht irrtuemlich bei
* manchen Window Managern vom Bildschirm genommen wird, bloss weil
* diese der OverrideShell den Tastaturfocus schenken bzw. diesen
* dem Combo-Box-Widget wegnehmen, sobald der Mauszeiger in die Liste
* bewegt wird.
*/
static void OverrideShellCallback(Widget w, XtPointer pClientData,
XEvent *event, Boolean *ContDispatch)
{
XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData;
switch ( event->type ) {
case EnterNotify:
LOG2("OverrideShellCallback: EnterNotify, PendingFO: %s\n",
cbw->combobox.PendingFocusOut ? "True" : "False");
if ( cbw->combobox.PendingFocusOut )
cbw->combobox.IgnoreFocusOut = True;
if ( cbw->combobox.TwmHandlingOn )
cbw->combobox.PendingOverrideInOut = True;
break;
case LeaveNotify:
LOG("OverrideShellCallback: LeaveNotify\n");
if ( cbw->combobox.TwmHandlingOn )
cbw->combobox.PendingOverrideInOut = True;
break;
}
} /* OverrideShellCallback */
/* --------------------------------------------------------------------
* Ha! Anscheinend kann man das Problem mit der einklappenden Liste,
* sobald man den Arrow-Button anklickt, doch loesen! Allerdings geht
* das auch nur von hinten durch die Brust in's Auge. Hier war die
* Reihenfolge der Events bislang das Problem: Klickt man den Arrow-
* Button an, so verliert das Eingabefeld den Focus, dann wird leider
* schon die WorkProc aktiviert und laesst die Liste verschwinden.
* Danach erst kommt der Arrow-Button-Callback an die Reihe. Um dieses
* Dilemma doch noch zu loesen, wird hier darauf gelauert, wann und
* welcher LeaveNotify kommt. Klickt der Benutzer den Pfeil an, so
* kommt hier noch rechtzeitig ein LeaveNotify vorbei, der aber durch
* einen Grab ausgeloest wurde. Und das ist eben nur beim Anklicken
* der Fall. Damit wissen wir, das der FocusOut getrost ignoriert
* werden darf.
* Puhhh -- ist das ein kompliziertes Chaos.
* Uebrigends...auch wenn manche Befehle zuerst ueberfluessig er-
* scheinen...sie sind erforderlich, damit die ComboBox auch mit unter-
* schiedlichen Window Managern zurechtkommt!
*/
static void ArrowCrossingCallback(Widget w, XtPointer pClientData,
XEvent *event, Boolean *ContDispatch)
{
XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData;
switch ( event->type ) {
case LeaveNotify:
LOG2("ArrowCrossingCallback: LeaveNotify, mode: %i\n",
event->xcrossing.mode);
if ( event->xcrossing.mode == NotifyGrab )
cbw->combobox.IgnoreFocusOut = True;
else
cbw->combobox.IgnoreFocusOut = False;
break;
}
} /* ArrowCrossingCallback */
/* --------------------------------------------------------------------
* Alle Hilfeaufrufe innerhalb der Kinder gehen an das eigentliche
* Combo-Box-Widget weiter, so dass auch hier nach aussen hin die
* Kinder-Widgets nicht in Erscheinung treten.
*/
static void HelpCallback(Widget w, XtPointer cbw, XtPointer CallData)
{
XtCallCallbacks((Widget) cbw, XmNhelpCallback, CallData);
} /* HelpCallback */
/* --------------------------------------------------------------------
* Wenn der Benutzer im Eingabefeld osfActivate drueckt, dann dieses
* Ereignis offiziell bekanntgeben.
*/
static void ActivateCallback(Widget w, XtPointer cbw, XtPointer CallData)
{
XtCallCallbacks((Widget) cbw, XmNactivateCallback, CallData);
} /* ActivateCallback */
/* --------------------------------------------------------------------
* Ein Kind moechte sein Groesse veraendern und fragt deshalb hier bei
* uns an.
* Parameter:
* w Naja...
* *Request Vorschlag des Kindes
* Ergebnis:
* *Reply Unsere Antwort darauf
* XtGeometryNo, da es uns bislang grundsaetzlich nie passt, es sei
* denn, es ist das Label... Naja, jetzt darf auch schon einmal das
* Listenfeld quengeln (aber nur, wenn es staendig sichtbar ist,
* ansonsten wird es nicht beruecksichtigt!).
*/
static XtGeometryResult GeometryManager(Widget w,
XtWidgetGeometry *Request,
XtWidgetGeometry *Reply)
{
XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w);
XtGeometryResult Result = XtGeometryNo;
/*
* Falls das Listenfeld statisch dargestellt wird, muessen wir seine
* Wuensche doch beruecksichtigen. Was fuer ein Aufwand...
*/
if ( (w == XtParent(cbw->combobox.ListCtrl)) && cbw->combobox.StaticList ) {
Dimension TotalWidth, TotalHeight, EditWidth, LabelWidth;
XtWidgetGeometry MyRequest, YourReply, EditGeom;
XtQueryGeometry(cbw->combobox.EditCtrl, NULL, &EditGeom);
DefaultGeometry(cbw, &TotalWidth, &TotalHeight,
&EditWidth, &LabelWidth);
CheckDropDownOffset(cbw);
if ( Request->request_mode && CWWidth )
if ( (Dimension)(LabelWidth + cbw->combobox.DropDownOffset +
Request->width) > TotalWidth )
TotalWidth = LabelWidth + cbw->combobox.DropDownOffset +
Request->width;
if ( Request->request_mode && CWHeight )
TotalHeight = EditGeom.height + Request->height;
/*
* Bastele nun eine Anfrage an Pappi zusammen und geh' ihm damit auf den
* Keks. Wenn er zustimmt, ist sofort alles gut, wir muessen dann nur
* noch das Layout aufpolieren, damit das Listenfeld die neue Groesse
* bekommt. Wenn Pappi nur halb zustimmt, akzeptieren wir das und fragen
* ihn damit noch einmal....
*/
MyRequest.request_mode = CWWidth | CWHeight;
MyRequest.width = TotalWidth;
MyRequest.height = TotalHeight;
Result = XtMakeGeometryRequest((Widget) cbw, &MyRequest, &YourReply);
if ( Result == XtGeometryAlmost ) {
MyRequest.width = YourReply.width;
MyRequest.height = YourReply.height;
Result = XtMakeGeometryRequest((Widget) cbw, &MyRequest, &YourReply);
}
if ( Result == XtGeometryYes )
DoLayout(cbw);
} else
/*
* Ansonsten darf nur noch das Schriftfeld Ansprueche anmelden.
*/
if ( w != cbw->combobox.LabelCtrl )
return XtGeometryNo; /* Was ICH hier vorgegeben habe, gilt! */
else if ( cbw->combobox.ShowLabel ) { /* Naja, 'mal schauen! */
Dimension TotalWidth, TotalHeight, EditWidth, LabelWidth;
XtWidgetGeometry MyRequest;
if ( Request->request_mode & CWWidth ) {
DefaultGeometry(cbw, &TotalWidth, &TotalHeight,
&EditWidth, &LabelWidth);
TotalWidth = TotalWidth - LabelWidth +
Request->width;
MyRequest.request_mode = CWWidth;
MyRequest.width = TotalWidth;
Result = XtMakeGeometryRequest((Widget) cbw, &MyRequest, NULL);
if ( Result == XtGeometryYes )
DoLayout(cbw);
}
}
return Result;
} /* GeometryManager */
/* --------------------------------------------------------------------
* Hier werden auf Wunsch diejenigen Farben, die bei der Combo-Box neu
* gesetzt wurden, an alle Kinder weitergegeben.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -