📄 xmcombo.c
字号:
* 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. */#define BOTTOMSHADOWCOLOR 0x0001#define TOPSHADOWCOLOR 0x0002#define FOREGROUND 0x0004#define BACKGROUND 0x0008static struct { String Resource; int Flag; } ColorResources[] = { { XmNbottomShadowColor, BOTTOMSHADOWCOLOR }, { XmNtopShadowColor, TOPSHADOWCOLOR }, { XmNforeground, FOREGROUND }, { XmNbackground, BACKGROUND } };static int UpdateColors(XmComboBoxWidget w, int flags){ Pixel Color, White, Black, EditCol; int i, size = XtNumber(ColorResources); Widget ScrolledWin, ScrollBar; ScrolledWin = XtParent(w->combobox.ListCtrl); XtVaGetValues(ScrolledWin, XmNverticalScrollBar, &ScrollBar, NULL); White = WhitePixel(XtDisplay(w), WidgetToScreen((Widget) w)); Black = BlackPixel(XtDisplay(w), WidgetToScreen((Widget) w)); for ( i=0; i<size; i++ ) if ( flags & ColorResources[i].Flag ) { if ( ColorResources[i].Flag == BACKGROUND ) EditCol = White; else if ( ColorResources[i].Flag == FOREGROUND ) EditCol = Black; else EditCol = Color; XtVaGetValues((Widget) w, ColorResources[i].Resource, &Color, NULL); XtVaSetValues(ScrollBar, ColorResources[i].Resource, Color, NULL); XtVaSetValues(w->combobox.ListCtrl, ColorResources[i].Resource, EditCol, NULL); XtVaSetValues(w->combobox.EditCtrl, ColorResources[i].Resource, EditCol, NULL); XtVaSetValues(ScrolledWin,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -