⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xmcombo.c

📁 Wxpython Implemented on Windows CE, Source code
💻 C
📖 第 1 页 / 共 5 页
字号:
 * in der die Drop-Down-Liste steckt. Und da nur Geschwisterfenster (sibling
 * windows) im gleichen Stapel stecken, reicht das Shellfenster nicht aus.
 * Alle gaengigen Fenstermanager sind solche "reparenting wm's", so dass ich
 * hier zu diesem Trick greifen kann, um die Drop-Down-Liste immer ueber der
 * ComboBox zu halten.
 *
 * Parameter:
 *   w			Diejenige Combo-Box, fuer die wir dasjenige
 *			Fenster des Window-Managers ermitteln sollen,
 *			dass direkt unterhalb des Root-Fensters liegt.
 * Ergebnis:
 *   besagtes zu suchendes Fenster, dass die Dekoration enthaelt (hoffentlich
 *   nur echte Bruesseler Spitze!)
 */
static Window GetDecorationWindow(XmComboBoxWidget w)
{
    Window       Root, Parent, AWindow;
    Window       *Children;
    unsigned int NumChildren;
    
    Parent = XtWindow((Widget) w);
    /* Suche nach dem Dekorationsfenster des Window-Managers */
    do {
	AWindow = Parent;
	XQueryTree(XtDisplay((Widget) w), AWindow, 
		   &Root, &Parent, &Children, &NumChildren);
	XFree((char *) Children);
    } while ( Parent != Root );
    return AWindow;
} /* GetDecorationWindow */

/* --------------------------------------------------------------------
 * Eine Combo-Box aus dem Wege raeumen...
 * Momentan muessen wir hier nur den Cursor wieder los werden sowie
 * eventuell reservierte Pixmaps.
 * Ups -- natuerlich muss auch wieder der Callback entfernt werden, 
 * der noch an der Shell haengt.
 */
static void Destroy(XmComboBoxWidget w)
{
/*    fprintf(stderr, "Destroy: %08X\n", w->core.window);*/
    if ( w->combobox.ConvertBitmapToPixmap )
	XFreePixmap(XtDisplay((Widget) w), 
	            w->combobox.LabelPixmap);
    if ( w->combobox.ConvertBitmapToPixmapInsensitive )
	XFreePixmap(XtDisplay((Widget) w), 
	            w->combobox.LabelInsensitivePixmap);
    if ( w->combobox.PendingFocusOut )
	XtRemoveWorkProc(w->combobox.WorkProcID);
    XtRemoveEventHandler(w->combobox.MyNextShell, 
                      StructureNotifyMask | FocusChangeMask, 
		      True, (XtEventHandler) ShellCallback, 
		      (XtPointer) w);
} /* Destroy */

/* ---------------------------------------------------------------------------
 * Ueberpruefe, ob fuer die Ressource "DropDownOffset" ein gueltiger Wert vom
 * Benutzer angegeben wurde. Diese Ressource gibt an, wie weit die Drop-Down-
 * Liste nach rechts gegenueber dem Eingabefeld eingerueckt sein soll. Wenn
 * hierfuer ein negativer Wert angegeben ist, so berechne statt dessen einen
 * Standardwert: dieser entspricht der Breite der Pfeilschaltflaeche, was 
 * optisch ganz gut wirkt (jedenfall nach meinem Dafuerhalten).
 */
static void CheckDropDownOffset(XmComboBoxWidget w)
{
    if ( w->combobox.DropDownOffset < 0 ) {
	XtWidgetGeometry ArrowGeom;
	
	XtQueryGeometry(w->combobox.ArrowCtrl, NULL, &ArrowGeom);
	w->combobox.DropDownOffset = ArrowGeom.width;
    }
} /* CheckDropDownOffset */

/* --------------------------------------------------------------------
 * Berechne die voreinzustellende Groesse, die diese Combo-Box be-
 * sitzen muss, um ausreichenden Raum fuer das Eingabefeld und den
 * Pfeil rechts daneben zur Verfuegung zu stellen. Bei einer
 * editierbaren Combo-Box ist zwischen dem Eingabefeld und dem Pfeil
 * noch ein Angst-Rasen von der halben Breite eines Pfeiles vorhanden.
 * Wird das Listenfeld staendig dargestellt, so entfallen sowohl Pfeil
 * als auch der Angstrasen, dafuer muss aber die Hoehe des Listenfelds
 * beruecksichtigt werden.
 */
static void DefaultGeometry(XmComboBoxWidget w, 
                            Dimension *TotalWidth, 
			    Dimension *TotalHeight, 
			    Dimension *EditCtrlWidth, 
			    Dimension *LabelCtrlWidth)
{
    XtWidgetGeometry EditGeom, ArrowGeom, LabelGeom, ListGeom;
    
    XtQueryGeometry(w->combobox.EditCtrl,  NULL, &EditGeom);
    XtQueryGeometry(w->combobox.ArrowCtrl, NULL, &ArrowGeom);
    XtQueryGeometry(w->combobox.LabelCtrl, NULL, &LabelGeom);

    /*
     * Soll die Pfeilschaltflaeche quadratisch, praktisch, gut sein?
     */
    if ( w->combobox.SquareArrow )
        ArrowGeom.width = ArrowGeom.height;
    else
        ArrowGeom.width = (ArrowGeom.height * 4) / 5;

    /*
     * Zuerst einmal ein paar einfache Werte ermitteln und zurueckgeben...
     */    
    *TotalHeight    = EditGeom.height;
    *EditCtrlWidth  = EditGeom.width;
    *LabelCtrlWidth = LabelGeom.width;

    /*
     * Ermittele nun die Breite, welche die Combobox benoetigt. Je nach-
     * dem, ob das Eingabefeld oder die Liste breiter sind, wird der
     * entsprechende Wert genommen. Diese Auswahl zwischen der Breite von
     * Eingabefeld und Liste findet aber nur statt, wenn die Liste auch
     * wirklich staendig sichtbar ist. Waehrend der Initialisierung hat
     * allerdings XmNcolumns, so dass in diesem Moment die List nicht
     * mehr die Breite kontrollieren kann!
     */
    if ( w->combobox.StaticList ) {
	/*
	 * Beachte: Frage nicht die Listbox, sondern das ScrolledWindow, 
	 * in welchem die Liste eingebettet ist.
	 */
	CheckDropDownOffset(w);
	XtQueryGeometry(XtParent(w->combobox.ListCtrl), NULL, &ListGeom);
	if ( w->combobox.InInit ) {
	    *TotalWidth = EditGeom.width;
	} else {
            if ( EditGeom.width < (Dimension)
                                   (ListGeom.width + w->combobox.DropDownOffset) )
		*TotalWidth = ListGeom.width + w->combobox.DropDownOffset;
	    else
		*TotalWidth = EditGeom.width;
        }
	*TotalHeight += ListGeom.height;
    } else {
	/*
	 * Das Listenfeld interessiert uns hier nicht. Degegen sollte noch
	 * die Breite fuer den Pfeil und ein evtl. Angstrasen beachtet
	 * werden.
	 */
	*TotalWidth  = EditGeom.width + ArrowGeom.width;
	if ( w->combobox.Editable && w->combobox.ArrowSpacingOn )
	    *TotalWidth += ArrowGeom.width/2;
    }
    
    /*
     * Vergiss nicht, auch noch ein evtl. sichtbares Schriftfeld zu berueck-
     * sichtigen!
     */
    if ( w->combobox.ShowLabel )
	*TotalWidth += LabelGeom.width;
    
} /* DefaultGeometry */

/* --------------------------------------------------------------------
 * Anhand eines Widgets ermittele darueber die Screennummer desjenigen
 * Screens, auf dem das Widget erscheint.
 * Parameter:
 *   w			betroffenes Widget.
 * Ergebnis:
 *   Nummer desjenigen Screens, auf dem das Widget angezeigt wird.
 */
static int WidgetToScreen(Widget w)
{
    Screen  *screen;
    Display *display;
    int     NumScreens, i;
    
    screen = XtScreen(w); NumScreens = ScreenCount(XtDisplay(w));
    display = DisplayOfScreen(screen);
    for ( i = 0; i < NumScreens; ++i )
	if ( ScreenOfDisplay(display, i) == screen )
	    return i;
    XtError("WidgetToScreen: data structures are destroyed.");
    return 0; /* to avoid a compiler warning */
} /* WidgetToScreen */

/* --------------------------------------------------------------------
 * Positioniere die DropDown-Liste (soweit sie natuerlich auch momentan
 * sichtbar ist) so auf dem Bildschirm, dass sie sich unterhalb des
 * Eingabefeldes anschliesst.
 */
static void DoDropDownLayout(XmComboBoxWidget w)
{
    Position       abs_x, abs_y;
    Dimension      ArrowWidth, ListWidth, ListHeight;
    Dimension      ScreenHeight, LabelWidth;
    XWindowChanges WindowChanges;

    /* 
     * etwa nicht sichtbar ?!! Oder etwa immer sichtbar ?!!
     * Dann sind wir jetzt sofort fertig. 
     */
    if ( !w->combobox.ListVisible || w->combobox.StaticList ) return;
    /*
     * Finde zuerst einmal heraus, wo wir uns denn auf dem Bildschirm be-
     * finden sollen... Beachte dabei auch, dass eventuell die Liste zu schmal
     * werden koennte und gib' ihr dann ggf. eine Mindestbreite, damit es
     * keinen core-Dump gibt.
     */
    XtVaGetValues(w->combobox.ArrowCtrl, XmNwidth,  &ArrowWidth, NULL);
    XtTranslateCoords((Widget) w, 0, w->core.height, &abs_x, &abs_y);
    CheckDropDownOffset(w);
    ListWidth  = w->core.width - w->combobox.DropDownOffset - 2;
    abs_x     += w->combobox.DropDownOffset;
    if ( w->combobox.ShowLabel ) {
	XtVaGetValues(w->combobox.LabelCtrl, XmNwidth, &LabelWidth, NULL);
	ListWidth -= LabelWidth;
	abs_x     += LabelWidth;
    }
    if ( ListWidth < 20 ) ListWidth = 20;
    XtVaGetValues(XtParent(w->combobox.ListCtrl), XmNheight, &ListHeight, NULL);
    /*
     * Hier ueberpruefen wir noch, ob die Liste unten aus dem Bildschirm 
     * herausfallen wuerde. In dem Fall klappen wir die Liste oberhalb des
     * Eingabefeldes auf.
     */
    ScreenHeight = DisplayHeight(XtDisplay((Widget) w), 
                                 WidgetToScreen((Widget) w));
    if ( abs_y + ListHeight + 2 > ScreenHeight ) {
        int y;
        
        y = ((int) abs_y) - ListHeight - w->core.height - 1;
        if ( y < 0 ) y = 0;
        abs_y = (Position) y;
    }
    XtConfigureWidget(w->combobox.PopupShell, 
		      abs_x, abs_y, ListWidth, ListHeight, 1);
    /*
     * So...das hier dient der Kosmetik: hier sorgen wir dafuer, dass die
     * Liste auch wirklich immer direkt ueber der ComboBox innerhalb des
     * Fensterstapels schwebt. Siehe dazu auch die Erlaeuterungen und An-
     * merkungen in GetDecorationWindow().
     */
    if ( XtIsRealized((Widget) w) ) {
	WindowChanges.sibling    = GetDecorationWindow(w);
	WindowChanges.stack_mode = Above;
	XReconfigureWMWindow(XtDisplay((Widget) w), 
	    XtWindow(w->combobox.PopupShell), 
	    WidgetToScreen(w->combobox.PopupShell), 
	    CWSibling | CWStackMode, &WindowChanges);
    }
} /* DoDropDownLayout */

/* --------------------------------------------------------------------
 * Naja... diese Routine scheint ja bereits zu einer Institution beim
 * Schreiben von Composite-Widgets geworden zu sein.
 * 
 * Hier beim ComboBox-Widget ist die Aufgabe ziemlich einfach: es
 * genuegt, die Eingabezeile und den Pfeil-Button entsprechend inner-
 * halb des ComboBox-Widgets zu plazieren. Seit allerdings noch das
 * Textlabel hinzukommt, wird's langsam aufwendiger. Nun ja - da sich
 * das Listenfeld wahlweise auch statisch einblenden laesst, ist nun
 * noch mehr zu beruecksichtigen, wenn die Kinder-Widgets an ihre
 * Plaetze geschoben werden.
 */
static void DoLayout(XmComboBoxWidget w)
{
    Dimension        EditCtrlWidth, ArrowCtrlWidth, LabelCtrlWidth;
    Dimension        ComboBoxHeight;
    Dimension        BorderWidth;
    Dimension        HighlightThickness;
    Position         EditX;
    
    XtVaGetValues(w->combobox.ArrowCtrl,
                  XmNheight, &ArrowCtrlWidth, NULL);
    if ( !w->combobox.SquareArrow )
        ArrowCtrlWidth = (ArrowCtrlWidth * 4) / 5;
    XtVaGetValues(w->combobox.LabelCtrl, 
                  XmNwidth, &LabelCtrlWidth, NULL);
    
    /* 
     * In Abhaengigkeit davon, ob die ComboBox editierbar ist und ob das
     * Listenfeld staendig sichtbar sein soll, hier die Breite einzelner
     * Widgets bestimmen.
     */
    if ( w->combobox.StaticList ) {
	ComboBoxHeight = w->combobox.EditCtrl->core.height;
	EditCtrlWidth  = w->core.width;
    } else {
	ComboBoxHeight = w->core.height;
	EditCtrlWidth  = w->core.width - ArrowCtrlWidth;
    	if ( w->combobox.Editable && w->combobox.ArrowSpacingOn )
    	    EditCtrlWidth -= ArrowCtrlWidth/2;
    }
    /* Beruecksichtige noch ein evtl. ebenfalls anzuzeigendes Schriftfeld
     * neben dem Eingabefeld.
     */
    if ( w->combobox.ShowLabel ) {
	EditX          = LabelCtrlWidth;
	EditCtrlWidth -= LabelCtrlWidth;
    } else
        EditX = 0;
    if ( EditCtrlWidth < 20 ) EditCtrlWidth = 20;
/* Plaziere nun das Eingabefeld... */
    XtVaGetValues(w->combobox.EditCtrl, 
                  XmNborderWidth,        &BorderWidth, 
		  XmNhighlightThickness, &HighlightThickness, 
		  NULL);
    XtConfigureWidget(w->combobox.EditCtrl, 
                      EditX, 0, 
		      EditCtrlWidth, ComboBoxHeight, BorderWidth);
/* ...und nun den Pfeil... */
    XtVaGetValues(w->combobox.ArrowCtrl, 
                  XtNborderWidth, &BorderWidth, NULL);
    XtConfigureWidget(w->combobox.ArrowCtrl, 
                      w->core.width-ArrowCtrlWidth, HighlightThickness, 
		      ArrowCtrlWidth, 
		      ComboBoxHeight - 2 * HighlightThickness, 
		      BorderWidth);
/* ...und ggf. das Textlabel. */
    if ( w->combobox.ShowLabel ) {
	XtVaGetValues(w->combobox.LabelCtrl, 
		      XmNborderWidth, &BorderWidth, 
		      NULL);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -