home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / prog / source / gadget.lha / GADGET.TXT < prev   
Text File  |  1987-03-08  |  18KB  |  447 lines

  1.      Fun with gadgets (Part 1)
  2.  
  3. '                    PHUN WITH GADGETS - John T. Draper
  4. ----------------------------------
  5.  
  6. Feel free to distribute this information onto any network.   Please
  7. check first to avoid duplication.   Would at least like credit for the
  8. 20 hours or so I took in preparing this section.
  9.  
  10. Gadgets are multi function input "devices" which run under Intuition.  There
  11. are four kinds,  and two flavers.
  12.  
  13. The flavers are:
  14.  
  15. 1) System gadgets - Those created for you when you create a window or screen
  16.  
  17. 2) User gadgets - Those gadgets YOU create and use in your program.   There
  18. are four kinds of these.
  19.  
  20.  
  21. The four kinds are:
  22.  
  23. 1) Boolean Gadgets - Usually "Yes/no" desisions,  "On/Off" buttons,  and
  24. other related uses.    They look like rectangles,  with text displayed
  25. (Or rendered), within those rectangles.
  26.  
  27. 2) Proportional Gadgets - Those which look like "Sliders" as displayed in
  28. the "R G B" Controls in the "Preferences" program.   I think Amiga should
  29. release the source to Preferences,  because It would be a very good example
  30. program.
  31.  
  32. 3) String gadgets - These allow text entry through the Keyboard.  Text can be
  33. automatically centered.
  34.  
  35. 4) Integer Gadget - A special form of string gadget that converts numeric text
  36. input into integers.
  37.  
  38.  
  39. USING GADGETS
  40. -------------
  41.  
  42. Each gadget has a data structure "Gadget",  which must first be declared
  43. and initialized.   There are several ways to do this.    The easiest way is
  44. to declare and initialize them like this:
  45.  
  46.  
  47. #define BLUE_GADGET 0         /* My own Gadget ID to mean this gadget */
  48. struct Gadget blue_gad = {
  49. NL, 17,112, 150,11, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
  50. PROPGADGET,(APTR)&b_img, NL,
  51. &btxt, NL,(APTR)&b_prop, BLUE_GADGET, NL
  52. };
  53.  
  54.  
  55. #define GREEN_GADGET 1        /* Another personal ID */
  56. struct Gadget green_gad = {
  57. &blue_gad, 17,97, 120,11, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
  58. PROPGADGET,(APTR)&g_img, NL,
  59. >xt, NL,(APTR)&g_prop, GREEN_GADGET, NL
  60. };
  61.  
  62.  
  63. #define RED_GADGET 2          /* And yet another gadget */
  64. struct Gadget red_gad = {
  65. &green_gad, 17,82, 90,11, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
  66. PROPGADGET,(APTR)&r_img, NL,
  67. &rtxt, NL,(APTR)&r_prop, RED_GADGET, NL
  68. };
  69.  
  70.  
  71. #define TEX_GAD 3
  72. struct Gadget tex_gad = {
  73. &red_gad, 10,10, 150,11, GADGHCOMP, STRINGCENTER | LONGINT,
  74. STRGADGET, NL, NL,
  75. NL, NL, (APTR)&TexString, TEX_GAD, NL
  76. };
  77.  
  78. The #define BLUE_GADGET 0,  etc,  are my own personal numbers that I
  79. want to use to identify these gadgets in my very own personal way.   I am
  80. using them for identification and to take action when the gadget is chosen
  81. via a C "Switch" statement.
  82.  
  83. Each "Element" in the structures declared above are separated by commas
  84. (For those not familiar with C),  and will be explained in detail.   In the
  85. above examples are Three Proportional Gadgets,  and a Text Gadget.  A more
  86. detailed description of each of the gadget fields are listed below.   It is
  87. pretty well explained in the Intuition manual.    Just a lack of examples
  88. showing how to build and detect them.
  89.  
  90. -- (NextGadget) First element is the "link" to the next gadget.  Last gadget
  91. has a Null (NL) for a link.   Note,  the last gadget is on the top.  The
  92. LAST Gadget should be set to NULL (NL).
  93.  
  94. -- (LeftEdge, TopEdge) - Specifies the LOCATION of the gadget relative to the
  95. window or screen,  in the above example,  "tex_gad.LeftEdge" has the
  96. value of 10.  The last gadget has LeftEdge = 17, TopEdge = 112 as shown
  97. above.
  98.  
  99. -- (Width, Height) - Specifies the Width and the height of the gadget select
  100. box.  In the above example,  the height remained the same,  and the Width
  101. progressively got smaller.  Width = 150, Height = 11 on the last one,
  102. then Width = 120, then eventually 90, See above.
  103.  
  104. -- (Flags) - Flags that you share with Intuition.to describe the appearance
  105. and behavior of the gadget.   GADGHCOMP is a flag that complements all
  106. of the bits contained within the gadget's select box.
  107.  
  108. -- (Activation) - Other flags that are used to activate certain features of
  109. the gadget.  GADGIMMEDIATE | RELVERIFY mean that we set BOTH those "Bits".
  110.  
  111. -- (GadgetType) - Describes the type of gadget.   In the example above,
  112. STRGADGET is one of the four types of gadgets that describe "string" or
  113. "Text".
  114.  
  115. -- (GadgetRender) - Points to an intuiImage.   This is what gets written onto
  116. screen or window as the gadget.  In the case where we use the proportional
  117. gadget, we supply the address of the Image Structure without initializing
  118. it.   It then gets rendered as a rectangle.
  119.  
  120. -- (SelectRender) - In this example, we put a NULL (NL) in this field.   If
  121. we wanted, we could put in another image.  This image would be displayed
  122. during highlighting (When mouse button is pressed in the gadget's select
  123. box).
  124.  
  125. -- (GadgetText) - A pointer to an "Intuitext" structure that describes any
  126. text that might be rendered when the gadget is rendered.
  127.  
  128. -- (MutualExclude) - In this example, we place a NULL (NL).  There are 32
  129. bits that can be used to "Turn off" other gadgets if this gadget gets
  130. selected.
  131.  
  132. -- (SpecialInfo) - A pointer to more information about proportional (PropInfo)
  133. and text (StringInfo).
  134. gadgets.
  135.  
  136. -- (GadgetID) - User definable ID Field.   It can be used to identify the
  137. gadget from the gadget pointer.   I use it as an argument to the
  138. "switch" statement,  because using an address (Or any large number) as
  139. arguments to the "switch" statement will cause the syst
  140.  
  141.  
  142.  
  143. *****  Fun with gadgets (Part 2)  *******
  144.  
  145. -- (GadgetID) - User definable ID Field.   It can be used to identify the
  146. gadget from the gadget pointer.   I use it as an argument to the
  147. "switch" statement,  because using an address (Or any large number) as
  148. arguments to the "switch" statement will cause the system to crash.
  149. It's a bug in the Lattice C compiler.
  150.  
  151. -- (UserData) - A pointer to data that can be of any user definable
  152. structure or data.
  153.  
  154. There are other structures needed for gadgets which are "SpecialInfo"
  155. types of structures.   They are: PropInfo, and StringInfo structures.
  156. These describe in detail more information on Proportional structures
  157. and Text structures.   Addresses of these structures will be put in the
  158. "SpecialInfo" field of the gadget structure.   For instance,  in the
  159. example above where the gadgets are declared and initialized, (APTR)&r_img
  160. is used in the "red_gad" declaration.   Where "r_img" is declared as follows:
  161.  
  162. struct Image    r_img, g_img, b_img;
  163.  
  164. In this particular example,  these are Images used by Intuition.  Sometimes
  165. YOU have to declare your own image.   Other times,  such as in the case above,
  166. Intuition initializes these images.   On first reading of the Intuition
  167. manual,
  168. it is not evident that These are initialized.
  169.  
  170.  
  171.  
  172.  
  173. PropInfo Structure:
  174. -------------------
  175.  
  176. A PropInfo structure contains specific information about a proportional
  177. gadget.   Such as a slider arm,  or a volume control.
  178.  
  179. -- (flags) - A set of flags like:
  180.  
  181. AUTOKNOB - If you want to use a generic default knob.   It's essentually
  182. a rectangle that fills the body of the proportional gadget.   If you set
  183. this flag,  Intuition will initialize the rest of this structure.
  184. A piece of code in the Example GAD.C shows where Three proportional
  185. structures are initialized.   These structures are named:
  186. "r_prop", "g_prop", and "b_prop".
  187.  
  188. Must initialize the proportional "SpecialInfo" structure
  189. before opening up the windows.
  190. r_prop.Flags = g_prop.Flags = b_prop.Flags = FREEHORIZ | AUTOKNOB;
  191. r_prop.HorizBody = g_prop.HorizBody = b_prop.HorizBody = 0x1000;
  192. r_prop.HorizPot = g_prop.HorizPot = b_prop.HorizPot = 0x8000;
  193.  
  194.  
  195. FREEHORIZ - Set this flag if you only want the "slider" or "Pot" to
  196. slide horizontally.
  197.  
  198. FREEVERT - Set this flag if you want to slide vertically only.
  199.  
  200. PROPBORDERLESS - Set this flag if you don't want borders.
  201.  
  202. KNOBHIT - Check this flag if you want to know if the mouse button is
  203. on the knob.
  204.  
  205. For example,  if you want a standard slider which is horizontally placed
  206. in the window,  set the flags:  AUTOKNOB | FREEHORIZ
  207.  
  208. If you are using a custom gadget, for instance a "joystick" that can move
  209. BOTH horizontally and vertically like the source code example in this lesson.
  210. then set the flags:  FREEHORIZ | FREEVERT.
  211.  
  212. -- (HorizPot) - Horizontal Position value for the gadget.
  213.  
  214. -- (VertPot)  - Vert Position value for the gadget.
  215.  
  216. -- (horizBody) - The incremental width of the gadget.   If set to 0x1000,
  217. means that the pot will move 1/16th of the full position if the mouse
  218. was pressed between the slider and the side of the gadget.   it always
  219. moves "towards" the point where the mouse was pressed.  The "joystick"
  220. custom gadget in the example sort of "Follows" the mouse.
  221.  
  222. -- (VertBody) - Vertical incremental width of the gadget.
  223.  
  224. The following fields are set by Intuition and are accessable to the
  225. user if needed.
  226.  
  227. -- (cWidth) - Container width.
  228.  
  229. -- (cHeight) - Container height.
  230.  
  231. -- (HPotRes, VPotRes) - Horiz and Vert increments.
  232.  
  233. -- (LeftBorder, TopBorder) - Container borders.
  234.  
  235. Here is a PropInfo structure for a custom designed joystick.
  236.  
  237. struct PropInfo cust_prop = {
  238. FREEHORIZ | FREEVERT,            /* Want knob to go both vert and horiz */
  239. 0x8000,  0x8000,                 /* Want knob to be centered initially  */
  240. 0x800,   0x800,                  /* Smallest increment the knob can move */
  241. 150, 50,                         /* cWidth, cHeight - Container w & h */
  242. 1, 1,                            /* HPosres, VPotres - Pot increments */
  243. 0, 0                             /* Container borders  */
  244. };
  245.  
  246. You can stick this anywhere in the global declarations section of your
  247. program.  Because of the limitations of the Lattice C compiler,  It should
  248. be declared "Before" the Gadget structure that uses it.
  249.  
  250. An important thing to remember about constructing gadgets is that the
  251. Coordinates in the Gadget structure are relative to the coordinates in the
  252. Window or Screen.
  253.  
  254. The coordinates in the border, or intuitext structure used by gadgets
  255. are RELATIVE to the Gadgets and NOT the window.   For instance,  if you
  256. want text to be displayed OVER the gadget rectangle,  your Y coords will
  257. be about -8 to -10,  while your x coords will be positive.   The point where
  258. text is written is at the UPPER LEFT section of the letters and NOT the
  259. lower left portion of the letters like in the Macintosh.
  260.  
  261. If you use borders around your gadgets, make sure you make room for
  262. at least one pixel around the "Selection box".   Because, when the user
  263. presses in the box,  it is inversed, and if the border coincides with
  264. a pixel in the selection box,   that pixel overlaps and turns into
  265. another color, thus making it look a bit cludgey.
  266.  
  267.  
  268.  
  269.  
  270. HOW TO CREATE GADGETS IN YOUR PROGRAM
  271. -------------------------------------
  272.  
  273. FIRST OFF - Sketch out an approximate picture showing approximately
  274. what the overall layout of the gadgets should look like.    Eventually,
  275. we will write a Gadget Editor,   but for now,   lets make one up the
  276. old fashion way.
  277.  
  278. Define gadget structures for each gadget.   Set the gadget flags
  279. appropriately,  specify pointers to Special structures, like "PropInfo"
  280. or "StringInfo" structure in the "SpecialInfo" field.   If you have
  281. custom images that you have created,   you need to declare a pointer
  282. to the image.
  283.  
  284. When you declare the gadgets,  you create the LAST gadget first in
  285. your Source code.   Each sucessive gadget then "Links" to the one in
  286. front of it.   The last gadget pointer is a NULL.   After each of the
  287. gadgets are linked properly,  then:
  288.  
  289. Declare any custom images,  borders,  or Text associated with the
  290. gadget.   This section of code shows an example of this.   Remember,  this
  291. portion of code should come BEFORE any of the gadget declarations because
  292. the C compiler doesn't seem to be able to forward reference.
  293.  
  294. Image for a custom proportional gadget
  295. --------------------------------------
  296. UWORD custimage[] = {
  297. 0x0000, 0x0000, 0x0180, 0x0660, 0x1818, 0x2004, 0x4002, 0x4002,
  298. 0x4002, 0x4002, 0x2004, 0x1818, 0x0660, 0x0180, 0x0000, 0x0000
  299. };
  300.  
  301. struct Image cus_image = {
  302. 0, 0,
  303. 16, 16, 1,                /* LeftEdge, TopEdge */
  304. &custimage[0],           /* Pointer to bit image */
  305. 1,  0,                   /* PlanePick, Planeonoff */
  306. NULL                     /* No other images */
  307. };
  308.  
  309. One of the gadgets that use the above image:
  310.  
  311. #define CUST_KNOB 4
  312. struct Gadget cust_knob = {
  313. &tex_gad, 17, 140, 150, 50, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
  314. PROPGADGET, (APTR)&cus_image, NL,
  315. &cus2_txt, NL, (APTR)&cust_prop, CUST_KNOB, NL
  316. };
  317.  
  318. Now,  we have to make sure the very first gadget is linked to our window
  319. OR SCREEN.   In this particular example,  we are only using a window,  and
  320. are using the Intuition WorkBench Screen.   The NewWindow structure is
  321. declared
  322. further down in the Code as shown below.   Making the assumption that the
  323. gadget shown above is the FIRST gadget (last in listing),  then the New
  324. Window structure is shown as below.
  325.  
  326.  
  327. struct NewWindow nw = {
  328. 0, 0,                  /*  Start position                      */
  329. 320, 200,              /*  width, height,                      */
  330. 0, 1,                  /*  detail, block pens                  */
  331. CLOSEWINDOW            /*  IDCMP flags                         */
  332. | REFRESHWINDOW
  333. | MOUSEBUTTONS
  334. | MOUSEMOVE
  335. | GADGETDOWN     <--  MUST SET THIS ONE
  336. | GADGETUP,      <--  AND THIS ONE
  337. /*  Regular flags for gadgets and such           */
  338. WINDOWDEPTH
  339. | WINDOWSIZING
  340. | WINDOWDRAG
  341. | REPORTMOUSE    <-- AND THIS ONE
  342. | WINDOWCLOSE
  343. | SMART_REFRESH,
  344.  
  345. &cust_knob,            /* First gadget in list  <-- WE DO IT HERE       */
  346. NULL,                  /* User checkmark                                */
  347. "Fun with Gadgets",    /* Window Title                                  */
  348. NULL,                  /* Pointer to screen (Set later)                 */
  349. NULL,                  /* Pointer to superbitmap                        */
  350. 0, 0, 320, 186,        /* Ignored because not sizeable                  */
  351. WBENCHSCREEN,          /* Using the Workbench screen                    */
  352. };
  353.  
  354. The example program given uses a different First Gadget2dCC   The last thing
  355. you should do is set the appropriate flags.   That is
  356. shown above.
  357.  
  358. RESPONDING TO THOSE GADGETS
  359. ---------------------------
  360.  
  361. Last but not least,  you need to be able to respond, read, or act on
  362. a gadget.   This is done by "Listening" to a gadget port.   A particular
  363. bit comes to you in a Message class field.   You must recieve this "message"
  364. from Intuition telling you that the user "clicked" the mouse in a particular
  365. gadget.   You don't know which one yet.   But you snatch that "message"
  366. by detecting a certain bit in the message.class field.   You tuck this
  367. value away for later use and "Reply" to the message, using the
  368. ReplyMsg function.  We keep doing this over and over until the user
  369. closes the window.   This is called an "Event loop".
  370.  
  371.  
  372.  
  373. for (;;)
  374. {
  375.  
  376. if (message = (struct IntuiMessage *)GetMsg(w->UserPort))  {
  377. MessageClass = message->Class;
  378. code = message->Code;
  379. ReplyMsg(message);
  380. switch (MessageClass) {
  381.  
  382. case GADGETUP    :
  383. case GADGETDOWN  : do_gadgets(message, w);
  384. break;
  385.  
  386. case CLOSEWINDOW : close_things();
  387. exit(0);
  388. break;
  389. case MOUSEBUTTONS: break;
  390. }   /* Case */
  391. }  /* if */
  392. }  /* for */
  393. } /* main */
  394.  
  395. In the Message,  contains the Address of the gadget chosen by the user.
  396. You pass the Message and the Window into a function called do_gadgets.
  397. This function identifies the gadget,  then acts on it in the appropriate
  398. way.    This function is listed below.   I basically grab the address of
  399. the particular structure,  then look for that special private code that
  400. I described to identify the gadget.
  401.  
  402. HANDLE THE GADGETS
  403. ------------------
  404. do_gadgets (mes, win)
  405.  
  406. struct IntuiMessage *mes;        /* Pointer to Message structure */
  407. struct Window *win;              /* And a window structure       */
  408. {
  409. struct Gadget *igad;     /* Ptr to gadget that Intuition found    */
  410. int  gadgid;             /* ID Code identifying which gadget      */
  411. ULONG val;
  412.  
  413. igad = (struct Gadget *) mes->IAddress;      /* Ptr to a gadget      */
  414. gadgid = igad->GadgetID;    /* My own personal code for this gad  */
  415. val = (ULONG)TexString.LongInt;
  416. switch(gadgid) {
  417.  
  418. case GREEN_GADGET: break;
  419. case BLUE_GADGET : break;
  420. case TEX_GAD     : printf("got here ...\n");
  421. printf("val = %ld\n", val);
  422. break;
  423. }
  424. }
  425.  
  426. As each gadget is identified, a CASE statement selects the appropriate
  427. action to be taken depending on the gadget.   In many cases, the SAME
  428. action is usually performed on similar gadgets,   but in the above
  429. example,  I only handle 3 gadgets.   I could have exampled more,  but
  430. Good ol Lattice C has a nasty bug that won't let me use four cases
  431. without crashing.   This is why it takes so long to write programs on the
  432. Amiga.   But thats the price for being a pioneer.
  433.  
  434. Feel free to chop it up and hack it to death.   So gotta work on
  435. Menus tommorrow.   Only have the Amiga for 5 more days.   Next on
  436. my aggenda for learning is:
  437.  
  438. Menus
  439.  
  440. Requestors
  441.  
  442. Sound
  443.  
  444. This is it for now.   Have fun hacking,  and I will be back with more
  445. later.   Feel free to ask me questions,  and tell me your problems
  446. with gadgets so we can solve them.
  447.