📄 newtoggleb.c
字号:
/* * NewToggleB.c - Sieht nicht nur einfach besser aus als das Original aus der * Motif-Mottenkiste, sondern darueberhinaus koennen die * einzelnen Zustaende der "Ankreuzkaestchen" und "Radio- * schalter" von den Anwender einfacher erfasst werden. Warum * eigentlich nicht gleich so?! * Und wer hat da denn vor einiger Zeit in den NetNews auf * die Anfrage eines gestressten Programmierers gesuelzt, dass * man ToggleButtons nicht ableiten kann und soll...? Ha! Es * geht eben doch (Greetings to Leonardo DaVinci...) Alles * zwar mangels Dokumentation eines der letzten wahren Aben- * teuer unserer Zeit, aber das Ergebnis kann sich doch sehen * lassen, oder?! * * Version 0.91b * Aktueller Zustand: * 16.05.1994 ToggleButton-Klasse mit 3 Zustaenden sowie einem besseren * Aussehen implementiert. Ausserdem ist der ToggleButton auch * in Menues einsetzbar! Arbeitet auch mit XmNradioBehavior * in RowColumn-Widgets! * * (c) 1994 Harald Albrecht * Institut fuer Geometrie und Praktische Mathematik * RWTH Aachen, Germany * albrecht@igpm.rwth-aachen.de * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file COPYING for more details); * if not, write to the Free Software Foundation, Inc., 675 Mass Ave, * Cambridge, MA 02139, USA. * */#include "NewToggleBP.h"#include <Xm/BaseClassP.h>#include <Xm/DrawP.h>#include <Xm/MenuUtilP.h>/* --------------------------------------------------------------------------- * Resourcen-Liste... * Hier werden diejenigen Resourcen definiert, die von "aussen" - also * fuer den Programmierer oder Anwender - benutzbar und veraenderbar * sind. * * Der Aufbau der einzelnen Eintraege ist immer wieder gleich: * Resourcen-Name XmN... oder XtN * Resourcen-Klasse XmC... oder XtC * Resourcen-Type XmR... oder XtR (Datentyp der Variable in der * struct der jeweiligen Widgetinstanz) * Resourcen-Groesse aktuelle Groesse dieses Datentyps * Resourcen-Offset Lage der Variable innerhalb der struct der * Widgetinstanz * Defaultwert-Type Typ des Defaultwertes * Defaultwert (normalerweise) Zeiger auf den Defaultwert */#define offset(field) XtOffsetOf(XmNewToggleButtonRec, field)static XtResource resources[] = { { /* Ist es ein normaler Toggle-Button (bzw. Radio-Button) oder hat * er 3 Zustaende (= Kompatibilitaet zu anderen Oberflaechen) ? */ XmNtriState, XmCTriState, XmRBoolean, sizeof(Boolean), offset(new_toggle.TriState), XmRString, "False" },/* { XmNselectColor, XmCSelectColor, XmRPixel, sizeof(Pixel), offset(toggle.select_color), XtRCallProc, _XmForegroundColorDefault }, */ { XmNshowReflection, XmCShowReflection, XmRBoolean, sizeof(Boolean), offset(new_toggle.ShowReflection), XmRString, "True" }, { XmNswapShadows, XmCSwapShadows, XmRBoolean, sizeof(Boolean), offset(new_toggle.SwapShadows), XmRString, "True" }}; /* resources */ /* --------------------------------------------------------------------------- * Funktions-Prototypen fuer die 'Methoden' des ComboBox-Widgets. Eigentlich * sind das in unserem Falle gar nicht allzu viele. Die meiste Arbeit wird * spaeter von den einzelnen Action-Routinen geleistet, die durch bestimmte * Ereignisse (oder Ereignistransitionen) ausgeloest werden. */static void ClassPartInit(WidgetClass);static void Repaint(XmNewToggleButtonWidget, XEvent *, Region);static Boolean SetValues(XmNewToggleButtonWidget, XmNewToggleButtonWidget, XmNewToggleButtonWidget, ArgList, Cardinal *);/* --------------------------------------------------------------------------- * Diese Funktions-Prototypen stellen neue "Methoden" dar, die erstmalig von * dieser ToggleButton-Ersatzklasse eingefuehrt werden. */static void DrawIndicator(XmNewToggleButtonWidget);static void DrawText(XmNewToggleButtonWidget);/* --------------------------------------------------------------------------- * Hier versammeln sich alle Translations, die entweder neu hinzukommen oder * aber von XmLabel ererbt wurden. Zu beachten ist, dass diejenigen Trans- * lationen, die bereits XmPrimitive kennt, zumindest innerhalb der Klassen- * struktur geerbt werden. Allerdings werden nichts desto trotz bei allen * Nachkommen von XmLabel moeglicherweise einige Translationen von XmPri- * mitive wieder ueberschrieben. * Schluck: in der Tat koennen wir einfach diejenigen Translationen von * XmToggleButton uebernehmen, wir muessen lediglich dafuer Sorge tragen, * neue Action-Prozeduren zu registrieren. In diesem Fall werden dann * praktischerweise gleich die neuen Routinen benutzt. Ergo: es folgt hier * keine Translation-Tabelle... *//* --------------------------------------------------------------------------- * Hier werden nun alle sog. Action-Routinen aufgezaehlt, die diese Widget- * klasse neu definiert. Dabei werden zum Teil bereits bestehende Action- * routinen der Vorfahrenklasse ueberschrieben. * Zuvor (vor der Zuordnung) sind aber noch ein Prototypen vonnoeten, damit * der Compiler nicht meckert. */#define ACTIONPROC(proc) \ static void proc(XmNewToggleButtonWidget, XEvent *, String *, Cardinal *)ACTIONPROC(EnterWidget);ACTIONPROC(LeaveWidget);ACTIONPROC(ArmWidget);ACTIONPROC(DisarmWidget);ACTIONPROC(SelectWidget);ACTIONPROC(ArmAndActivateWidget);ACTIONPROC(BtnUpWidget);static XtActionsRec actions[] = { { "Enter", (XtActionProc) EnterWidget }, { "Leave", (XtActionProc) LeaveWidget }, { "Arm", (XtActionProc) ArmWidget }, { "Disarm", (XtActionProc) DisarmWidget }, { "Select", (XtActionProc) SelectWidget }, { "ArmAndActivate", (XtActionProc) ArmAndActivateWidget }, { "BtnUp", (XtActionProc) BtnUpWidget }}; /* actions *//* --------------------------------------------------------------------------- * Klassen-Definition unserer neuen ToggleButton-Klasse. */XmNewToggleButtonClassRec xmNewToggleButtonClassRec = { { /*** core-Klasse ***/ /* superclass */ (WidgetClass) &xmToggleButtonClassRec, /* class_name */ "XmNewToggleButton", /* widget_size */ sizeof(XmNewToggleButtonRec), /* class_initialize */ NULL, /* class_part_initialize */ (XtWidgetClassProc) ClassPartInit, /* class_inited */ False, /* IMMER mit FALSE initialisieren !! */ /* initialize */ NULL, /* initialize_hook */ NULL, /* realize */ (XtRealizeProc) XmInheritRealize, /* actions */ actions, /* num_actions */ XtNumber(actions), /* resources */ resources, /* num_resources */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ True, /* compress_exposure */ XtExposeCompressMultiple, /* compress_enterleave */ True, /* visible_interest */ False, /* destroy */ NULL, /* resize */ (XtWidgetProc) XmInheritResize, /* expose */ (XtExposeProc) Repaint, /* set_values */ (XtSetValuesFunc) SetValues, /* set_values_hook */ NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ NULL, /* accept_focus */ NULL, /* version */ XtVersion, /* callback_private */ NULL, /* tm_table */ NULL, /* query_geometry */ XtInheritQueryGeometry, /* display_accelerator */ XtInheritDisplayAccelerator, /* extension */ NULL }, { /*** xmPrimitive-Klasse ***/ /* border_highlight */ (XtWidgetProc) _XtInherit, /* border_unhighlight */ (XtWidgetProc) _XtInherit, /* translations */ XtInheritTranslations, /* arm_and_activate */ NULL, /* syn_resources */ NULL, /* num_syn_resources */ 0, /* extension */ NULL }, { /*** xmLabel-Klasse ***/ /* setOverrideCallback */ (XtWidgetProc) XmInheritSetOverrideCallback, /* menuProcs */ NULL, /* translations */ XtInheritTranslations, /* extension */ NULL }, { /*** xmToggleButton-Klasse ***/ /* foo */ 0 }, { /*** xmNewToggleButton-Klasse ***/ /* DrawIndicator */ XmInheritNewToggleButtonIndicatorDrawProc, /* DrawText */ XmInheritNewToggleButtonTextDrawProc }}; /* xmNewToggleButtonClassRec */WidgetClass xmNewToggleButtonWidgetClass = (WidgetClass) &xmNewToggleButtonClassRec;#include <stdio.h>/* --------------------------------------------------------------------------- * Diese Initialisierungsroutine wird immer dann aufgerufen, wenn entweder * diese Widgetklasse oder aber eine davon abgeleitete Klasse erstmalig in * "Betrieb" genommen wird. Hier sorgen wir dafuer, dass abgeleitete Klassen * die neu eingefuehrten Methoden erben koennen. Dabei handelt es sich um * Methoden, um sowohl den "Indikator" als auch den Text/Pixmap zu zeichnen. * Leider hat die OSF sowas naemlich bei ihrer ToggleButton-Klasse total * vergessen! Daher ja auch der ganze Aufwand hier!! * * Parameter: * wc Diejenige Widgetklasse, die erstmalig in Betrieb ge- * nommen werden soll. Dieses ist entweder die hier neu * eingefuehrte Klasse oder aber moeglicherweise eine * davon abgeleitete. */static void ClassPartInit(WidgetClass wc){ /* Sorge dafuer, dass die neu definierten Methoden von den Nachkommen * geerbt werden koennen. */ if ( ((XmNewToggleButtonClassRec *) wc)->newtoggle_class.DrawIndicator == XmInheritNewToggleButtonIndicatorDrawProc ) ((XmNewToggleButtonClassRec *) wc)->newtoggle_class.DrawIndicator = (XmNewToggleButtonIndicatorDrawProc) DrawIndicator; if ( ((XmNewToggleButtonClassRec *) wc)->newtoggle_class.DrawText == XmInheritNewToggleButtonTextDrawProc ) ((XmNewToggleButtonClassRec *) wc)->newtoggle_class.DrawText = (XmNewToggleButtonTextDrawProc) DrawText; /* ...eigentlich ja ueberfluessig, da bereits in den vorherigen Klassen * durchgefuehrt... aber schaden tut's auch nicht! */ _XmFastSubclassInit(wc, XmTOGGLE_BUTTON_BIT | XmLABEL_BIT | XmPRIMITIVE_BIT);} /* ClassPartInit *//* --------------------------------------------------------------------------- * Mit Hilfe dieser Routine kann anhand des aktuellen Zustands ermittelt * werden, in welchen Zustand der Button als naechstes uebergehen wird. * * Parameter: * w Widget, fuer den der naechste Zustand erfragt werden * soll. * State Der aktuelle Zustand. Hierzu bitte den folgenden * Zustand ermitteln. * * Ergebnis: * Der naechste Zustand des Buttons. */static Boolean ToggleButtonNextState(XmNewToggleButtonWidget w, Boolean State){ if ( w->new_toggle.TriState ) switch ( State ) { case XmTOGGLE_ON : return XmTOGGLE_OFF; case XmTOGGLE_OFF : return XmTOGGLE_DONTKNOW; case XmTOGGLE_DONTKNOW: default: return XmTOGGLE_ON; } switch ( State ) { case XmTOGGLE_ON : return XmTOGGLE_OFF; case XmTOGGLE_OFF : return XmTOGGLE_ON; case XmTOGGLE_DONTKNOW: default: return XmTOGGLE_ON; }} /* ToggleButtonNextState *//* --------------------------------------------------------------------------- * Zeichne den Indikator, das ist entweder ein Ankreuzkaestchen oder aber ein * runder Radioschalter. (Ach, waren das noch Zeiten, als man sich an den * Roehren die Finger waermen konnte und man noch zum Betrieb so richtig * Spannung brauchte -- nicht so laeppische 3,3V!!!) * * Parameter: * w Dasjenige Widget, fuer das der Indikator zu zeichnen * ist. Den aktuellen Zustand erfaehrt man aus der * Instanz-Struktur dieses Widgets aus der Variable * w->toggle.visual_state. */static void DrawIndicator(XmNewToggleButtonWidget w){ Display *Dsp = XtDisplay((Widget) w); Window Win = XtWindow((Widget) w); GC TopGC, BottomGC; Position x, y; Dimension size; Boolean State = w->toggle.visual_set; if ( !XtIsRealized(w) ) return; /* Zuerst muessen wir uns hier einmal die geeigneten GCs zusammenstellen, * mit deren Hilfe wir den sog. Indikator zeichnen. */ if ( (State == XmTOGGLE_OFF) || !(w->new_toggle.SwapShadows) || (w->label.menu_type != XmWORK_AREA) ) { TopGC = w->primitive.top_shadow_GC; BottomGC = w->primitive.bottom_shadow_GC; } else { TopGC = w->primitive.bottom_shadow_GC; BottomGC = w->primitive.top_shadow_GC; } /* Jetzt muessen wir noch berechnen, wo denn der Indikator zu zeichnen * ist. */ size = w->toggle.indicator_dim - 3 ; if ( w->label.menu_type != XmWORK_AREA ) size += 2; if ( size < 4 ) size = 4; x = w->label.margin_width + w->primitive.highlight_thickness; if ( w->label.string_direction == XmSTRING_DIRECTION_R_TO_L ) x = w->core.width - x - size; y = ((w->core.height - size) >> 1);/* XClearArea(Dsp, Win, x, y, size, size, False); */ /* Wir muessen hier dafuer sorgen, dass ein evtl. doch noch von * XtSetValues gezeichneter alter Indikator entsorgt wird! */ XClearArea(Dsp, Win, x, w->label.TextRect.y, w->toggle.indicator_dim, w->label.TextRect.height, False); if ( w->toggle.ind_type != XmONE_OF_MANY ) { /* Es ist ein sog. Ankreuzkaestchen. Hiervon koennen jeweils be- * liebig viele angekreuzt oder auch nicht angekreuzt sein. Dar- * gestellt werden sie konsequenterweise als Kaestchen. */ XDrawLine(Dsp, Win, TopGC, x, y, x + size, y); XDrawLine(Dsp, Win, TopGC, x, y, x, y + size); XDrawLine(Dsp, Win, BottomGC, x + size, y + 1, x + size, y + size); XDrawLine(Dsp, Win, BottomGC, x + 1, y + size, x + size, y + size); if ( State != XmTOGGLE_OFF ) if ( State != XmTOGGLE_ON ) XFillRectangle(Dsp, Win, w->label.insensitive_GC, x + 2, y + 2, size - 3, size - 3);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -