///////////////////////////////////////////////////////////////////////////// // // example // // This file demonstrates many of the features of the gem++ library. // ///////////////////////////////////////////////////////////////////////////// // // This file is Copyright 1992 by Warwick W. Allison, // and is freely distributable providing no charge is made. // ///////////////////////////////////////////////////////////////////////////// #include "gem++.h" #include "example.h" #include #include // // Demonstrates a simple derived class of GEMobject // // Objects of this class will become Checked when clicked upon. // class MenuItemToggle : public GEMobject { public: GEMfeedback Touch(int x, int y, const GEMevent& e) { Checked(bool(!Checked())); Deselect(); Redraw(); return ContinueInteraction; } }; static char* monthtext[12]={"JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"}; // // Demonstrates GEMtimer and GEMhotform used for popup menus. // // This class encapsulates all the RSCindices required to setup // the clock, so only of of these objects could be created, since // they use the single graphics in the GEMrsc. See the GEMringfiw // below for a more complex example that allows duplicates. // // This class has quite a few components... // // - it is a GEMformwindow with no window-parts, so it is a form // in a window. // - it is a GEMtimer, so its Expire() method is called at the intervals // requested with Interval(). // - it is a GEMobject based on the GRABBER object, so its Touch() method // is called when the GRABBER is touched. // - it has two GEMtextobjects, timetext and datetext, which we can just // treat as if they are char*'s since they have conversion operators. // - it has a GEMhotform, popup, used for a pop-up menu. // - it has a MenuItemToggle (defined above), gmt, which is in the popup // menu, and which we test the Checked() state of when deciding to // use local or Greenwich time. // - it has a GEMalert, gmjoke, which makes the whole GMT thing worthwhile. // // The member functions are described within. // class Clock : public GEMformwindow, GEMtimer, GEMobject { public: Clock(GEMactivity& act, const GEMrsc& rsc) : GEMformwindow(act,rsc,CLOCK,0), GEMtimer(act,0), // Initially interval==0, ie. Expire() immediately. GEMobject(*this,GRABBER), timetext(*this,TIME), datetext(*this,DATE), popup(rsc,POPUP), gmt(popup,GMT), gmjoke(rsc,GMJOKE) { strcpy(timetext," "); strcpy(datetext," "); } private: // The Update() method gets the local time or Greenwich time, according // to whether the gmt GEMobject is Checked. It then sets the timetext // and datetext strings (they are actually GEMtextobjects). It then // Redraws those strings. Update() is a local member, called by the // methods below it. // void Update() { time_t ti=time(0); tm* T; if (gmt.Checked()) T=gmtime(&ti); else T=localtime(&ti); timetext[0]=T->tm_hour/10 ? T->tm_hour/10+'0' : ' '; timetext[1]=T->tm_hour%10+'0'; timetext[2]=T->tm_min/10+'0'; timetext[3]=T->tm_min%10+'0'; strncpy(datetext,monthtext[T->tm_mon],3); datetext[3]=T->tm_mday/10 ? T->tm_mday/10+'0' : ' '; datetext[4]=T->tm_mday%10+'0'; if (IsOpen()) { timetext.Redraw(); datetext.Redraw(); } } protected: // The Expire() method overrides that inherited from GEMtimer. // It is called when the interval expires. Its action it // to merely Update the time and wait set the interval to // be 60000 milliseconds. We only need to reset the interval // because when we created the object, we requested the interval // to be 0 so that the Expire (and hence Update) would be // immediate. // virtual GEMfeedback Expire(const GEMevent&) { Update(); Interval(60000); // Every minute, approx. return ContinueInteraction; } // The Touch() method overrides that inheritted from GEMobject. // It is called whenever the user touches the GRABBER object // on which the object was defined. // // If the touch is made using the right button (button 1), the // popup menu is displayed. If the exitor of the popup is // the "close" menuitem, the Close() method inheritted from // GEMformwindow is called. If the exitor is the smiley-face // icon (DOGMJOKE, that's Do-GM-joke), the gmjoke alert is // popped up. If the exitor is the "quit" menuitem, EndInteraction // is returned, ending the GEMactivity.Do() loop. Note that // the "GMT" menuitem is handled by using the Touch() method of // MenuItemToggle as described above. // // If the touch is not made by the right button, we employ a bit // of AES code (hmm, maybe that ugly stuff needs a class) to drag // a box the size of the BorderRect of this window, then we // GEMformwindow::Move this window to that dragged location. // virtual GEMfeedback Touch(int x, int y, const GEMevent& e) { if (e.Button(1)) { switch (popup.Do(e.X(),e.Y())) { case QCLOCK: Close(); break; case DOGMJOKE: gmjoke.Alert(); break; case QPROG: return EndInteraction; } Update(); return ContinueInteraction; } else { int bx,by,bw,bh; int nx,ny; wind_get(0,WF_WORKXYWH,&bx,&by,&bw,&bh); GRect w=BorderRect(); graf_dragbox(w.g_w,w.g_h,w.g_x,w.g_y,bx,by,bw,bh,&nx,&ny); GEMformwindow::Move(nx,ny); return ContinueInteraction; } } private: GEMtextobject timetext,datetext; GEMhotform popup; MenuItemToggle gmt; GEMalert gmjoke; }; // // Demonstrates GEMvdiobject // class GEMliney : public GEMvdiobject { protected: virtual void Draw(int x, int y) { int j=Width() < Height() ? Width() : Height(); for (int i=0; iprev=this; prev->next=this; } ~GEMringfiw() { if (next==this) { head=0; } else { if (head==this) head=next; prev->next=next; next->prev=prev; } } public: static bool OpenNew(GEMactivity& act, const GEMrsc& rsc, int RSCform, int RSCicon, GEMringfiw*& head) { GEMringfiw* newhead; if (head) newhead=new GEMringfiw(*head,head); else newhead=new GEMringfiw(act,rsc,RSCform,RSCicon,head); head=newhead; head->Open(); if (head->IsOpen()) { return TRUE; } else { delete newhead; return FALSE; } } }; // // Demonstrates GEMmenu as central to the interaction. // class Menu : GEMmenu { public: Menu(GEMactivity& in, const GEMrsc& r) : GEMmenu(in,r,MENU), act(in), rsc(r), about(rsc,ABOUT), itisfree(rsc,FREE), authors(rsc,AUTHORS), gnu(rsc,GNU), errwin(rsc,ERRWIN), clocknote(rsc,CLOCKNOTE), various(in,rsc), clock(in,rsc), windows(0), bigform(in,rsc,BIGFORM,BIGFORMI,CLOSER|MOVER|NAME|FULLER|SIZER|UPARROW|DNARROW|LFARROW|RTARROW|VSLIDE|HSLIDE) { bigform.Resize(200,100); } protected: virtual GEMfeedback DoItem(int item, const GEMevent& e) { switch (item) { case DOABOUT: about.Do(); break; case DOFREE: itisfree.Do(); break; case DOAUTHORS: authors.Do(); break; case DOGNU: gnu.Do(); break; case DOQUIT: return EndInteraction; break; case DOVARIOUS: various.Open(); break; case DOBIGFORM: bigform.Open(); break; case DOSHARING: if (!GEMringfiw::OpenNew(act,rsc,SHARING,SHARINGI,windows)) switch (errwin.Alert()) { case 1: return DoItem(item,e); break; case 2: about.Do(); } break; case DOCLOCK: clocknote.Alert(); clock.Open(); } return ContinueInteraction; } private: Clock clock; GEMringfiw* windows; GEMactivity& act; GEMrsc& rsc; GEMform about,itisfree,authors,gnu; GEMformiconwindow bigform; Various various; GEMalert errwin; GEMalert clocknote; }; // // Demonstrates GEMfileselector // class FileChooser : public GEMobject, public GEMfileselector { public: FileChooser(GEMform& f, int RSCibutn, GEMobject& disp, char* prmpt) : GEMobject(f,RSCibutn), GEMfileselector(disp.Text()), display(disp), prompt(prmpt) { display.Redraw(); } virtual GEMfeedback Touch(int x, int y, const GEMevent& e) { if (Get(prompt)) display.Redraw(); return ContinueInteraction; } private: GEMobject& display; char* prompt; }; // // Demonstrates GEMdesktop // class Desktop : public GEMdesktop { public: Desktop(GEMactivity& in, const GEMrsc& rsc) : GEMdesktop(in,rsc,DESKTOP), display(*this,FILEDISPLAY), files(*this,FILES,display,rsc.String(FILEPROMPT)) { } private: GEMobject display; FileChooser files; }; main() { // Before we do ANYTHING with GEM, we must declare a GEMapplication. GEMapplication example; // Next, we declare a GEMrsc, which we then use to create other objects. GEMrsc rsc("example.rsc",8,16); // GEMrsc rsc("example.rsc"); if (!rsc) { // If the GEMrsc file cannot be created, we have to resort to a // GEMalert constructed from strings rather than from the GEMrsc. GEMalert dammit("Could not load \"example.rsc\".","Quit"); dammit.Alert(); } else { // But if everything goes fine, we create a GEMactivity, and // our own Menu and Desktop (see definitions above) in that // GEMactivity. GEMactivity activity; Menu menu(activity,rsc); Desktop desktop(activity,rsc); // Then, conduct the GEMactivity - returns when all done. activity.Do(); } }