/* * This function is based on the DrawIntro and DrawBlinds * functions in Vexed, a Cool GPL Palm Game by * "James McCombe" <*****@*****.**> * http://spacetube.tsx.org */ void DrawIntro () { VoidHand Title_Handle; BitmapPtr Title; char text[40]; SWord penx, peny; Boolean bstate; /* If a game is on, don't do the splash */ if( stor.currplayer >= 0 ) return; // load bitmap resource and get handle Title_Handle = DmGet1Resource ('Tbmp', bmpTitle); // lock the bitmap resource into memory and get a pointer to it Title = MemHandleLock (Title_Handle); // draw the bitmap ( 160x160 ) WinDrawBitmap (Title, 0, 0); /* Text Strings */ StrPrintF (text, IntroVersionString, VERSION); WinDrawChars (text, StrLen (text), 5, 6); StrPrintF (text, IntroForPalmString, 153); WinDrawChars (text, StrLen (text), 52, 50); StrPrintF (text, IntroTapHereString, VERSION); WinDrawChars (text, StrLen (text), 45, 85); // unload the bitmap from memory (unlock) MemHandleUnlock (Title_Handle); // Loop till screen is tapped while (bstate) EvtGetPen (&penx, &peny, &bstate); while (!bstate) EvtGetPen (&penx, &peny, &bstate); /* If the user clicked in the drawing area, then * do a Draw Blinds and clear the PenQueue. */ if( peny < 160 ) { // DrawBlinds int i, x; float delay; EvtFlushPenQueue(); delay = .01 * SysTicksPerSecond(); for (i = 0; i < 16; i++) { for (x = i; x < 160; x += 16) { WinEraseLine( 0,x, 159,x ); } SysTaskDelay(delay); } } /* if( peny < 160 ) */ }
void fastPoll( void ) { RANDOM_STATE randomState; BYTE buffer[ RANDOM_BUFSIZE + 8 ]; WinHandle winHandle; Coord xCoord, yCoord; Boolean flag; uint64_t ticks; nsecs_t nsTime; initRandomData( randomState, buffer, RANDOM_BUFSIZE ); /* Get the event-available and low-level event-available flag, current pen status, and handle of the window with the input focus */ flag = EvtEventAvail(); addRandomValue( randomState, flag ); flag = EvtSysEventAvail( TRUE ); addRandomValue( randomState, flag ); EvtGetPen( &xCoord, &yCoord, &flag ); addRandomValue( randomState, xCoord ); addRandomValue( randomState, yCoord ); winHandle = EvtGetFocusWindow(); addRandomValue( randomState, winHandle ); /* Get the number of ticks of the (software) millisecond clock used by the scheduler, and the length of time in nanoseconds since the last reset */ ticks = TimGetTicks(); addRandomData( randomState, &ticks, sizeof( uint64_t ) ); nsTime = SysGetRunTime(); addRandomData( randomState, &nsTime, sizeof( nsecs_t ) ); /* Get the value of the real-time and runtime clocks in nanoseconds. One of these may just be a wrapper for SysGetRunTime(), in addition it's likely that they're hardware-specific, being CPU-level cycle counters of some kind */ nsTime = system_real_time(); addRandomData( randomState, &nsTime, sizeof( nsecs_t ) ); nsTime = system_time(); addRandomData( randomState, &nsTime, sizeof( nsecs_t ) ); /* Flush any remaining data through */ endRandomData( randomState, 5 ); }
Boolean ExamsFormHandleEvent(EventPtr event) { FormPtr frm=FrmGetActiveForm(); Boolean handled = false; Boolean categoryEdited, reDraw=false; UInt16 category, numRecords; ControlType *ctl; UInt32 *recordList; if (event->eType == ctlSelectEvent) { // button handling switch (event->data.ctlSelect.controlID) { case BUTTON_ex_back: handled=true; FrmGotoForm(FORM_main); break; case BUTTON_ex_add: handled=true; if (CountCourses() > 0) { gExamsLastSelRowUID=0; FrmPopupForm(FORM_exam_details); } else { FrmAlert(ALERT_nocourses); } break; case BUTTON_ex_edit: handled=true; gExamsLastSelRowUID=TblGetRowData(GetObjectPtr(TABLE_exams), gExamsSelRow); FrmPopupForm(FORM_exam_details); break; case BUTTON_ex_note: { UInt16 index=0; handled=true; gExamsLastSelRowUID=TblGetRowData(GetObjectPtr(TABLE_exams), gExamsSelRow); DmFindRecordByID(DatabaseGetRefN(DB_MAIN), gExamsLastSelRowUID, &index); NoteSet(index, FORM_exams); FrmPopupForm(NewNoteView); break; } case BUTTON_ex_del: handled=true; gExamsLastSelRowUID=TblGetRowData(GetObjectPtr(TABLE_exams), gExamsSelRow); ExamDelete(); break; case BUTTON_ex_beam: handled=true; gExamsLastSelRowUID=TblGetRowData(GetObjectPtr(TABLE_exams), gExamsSelRow); ExamBeam(); break; case LIST_ex_cat_trigger: handled=true; category=DatabaseGetCat(); numRecords=DmNumRecordsInCategory(DatabaseGetRef(), DELETE_CATEGORY); recordList=(UInt32 *)MemPtrNew(numRecords * sizeof(UInt32)); CatPreEdit(numRecords, recordList); categoryEdited = CategorySelect(DatabaseGetRef(), frm, LIST_ex_cat_trigger, LIST_ex_cat, false, &category, gCategoryName, 0, STRING_cat_edit); // categoryDefaultEditCategoryString if (categoryEdited || (category != DatabaseGetCat())) { reDraw=true; DatabaseSetCat(category); ctl = GetObjectPtr(LIST_ex_cat_trigger); CategoryGetName(DatabaseGetRef(), category, gCategoryName); CategorySetTriggerLabel(ctl, gCategoryName); } CatPostEdit(numRecords, recordList); if (reDraw) { gExamsOffset=0; gExamsSelRow=0; FrmUpdateForm(FORM_exams, frmRedrawUpdateCode); } if (recordList != NULL) MemPtrFree((MemPtr)recordList); break; default: break; } } else if (event->eType == tblEnterEvent) { UInt16 i; if (event->data.tblEnter.column == EXCOL_DONE) { handled=false; } else if (event->data.tblEnter.column == EXCOL_NOTE) { MemHandle m; Boolean hasNote=false; gExamsSelRow=event->data.tblEnter.row; for (i=0; i < TblGetNumberOfRows(event->data.tblEnter.pTable); ++i) { RectangleType r; TblGetItemBounds(event->data.tblEnter.pTable, i, EXCOL_SELI, &r); TableDrawSelection(event->data.tblEnter.pTable, i, event->data.tblEnter.column, &r); } m = DmQueryRecord(DatabaseGetRefN(DB_MAIN), TblGetRowID(event->data.tblEnter.pTable, event->data.tblEnter.row)); if (m) { ExamDBRecord *ex = (ExamDBRecord *)MemHandleLock(m); if (ex->note) hasNote = true; else hasNote = false; MemHandleUnlock(m); } if (hasNote) { Coord newPointX, newPointY; Boolean isPenDown=false, drawn=false; RectangleType fieldBounds; IndexedColorType curForeColor, curBackColor, curTextColor; Char noteSymb[2] = { GADGET_NOTESYMBOL, 0 }; FontID oldFont; EvtGetPen(&newPointX, &newPointY, &isPenDown); TblGetItemBounds(event->data.tblEnter.pTable, event->data.tblEnter.row, EXCOL_NOTE, &fieldBounds); oldFont = FntSetFont(symbolFont); while (isPenDown){ if (! drawn && RctPtInRectangle(newPointX, newPointY, &fieldBounds)) { curForeColor = WinSetForeColor(UIColorGetTableEntryIndex(UIObjectSelectedForeground)); curBackColor = WinSetBackColor(UIColorGetTableEntryIndex(UIObjectSelectedFill)); curTextColor = WinSetTextColor(UIColorGetTableEntryIndex(UIObjectSelectedForeground)); TNDrawCharsToFitWidth(noteSymb, &fieldBounds); WinSetForeColor(curForeColor); WinSetForeColor(curBackColor); WinSetForeColor(curTextColor); drawn = true; } else if (drawn && ! RctPtInRectangle(newPointX, newPointY, &fieldBounds)) { curForeColor = WinSetForeColor(UIColorGetTableEntryIndex(UIObjectForeground)); curBackColor = WinSetBackColor(UIColorGetTableEntryIndex(UIObjectFill)); curTextColor = WinSetTextColor(UIColorGetTableEntryIndex(UIObjectForeground)); TNDrawCharsToFitWidth(noteSymb, &fieldBounds); WinSetForeColor(curForeColor); WinSetForeColor(curBackColor); WinSetForeColor(curTextColor); drawn = false; } EvtGetPen(&newPointX, &newPointY, &isPenDown); } FntSetFont(oldFont); } else { handled = true; } } else { gExamsSelRow=event->data.tblEnter.row; for (i=0; i < TblGetNumberOfRows(event->data.tblEnter.pTable); ++i) { RectangleType r; TblGetItemBounds(event->data.tblEnter.pTable, i, EXCOL_SELI, &r); TableDrawSelection(event->data.tblEnter.pTable, i, event->data.tblEnter.column, &r); } handled=true; } } else if (event->eType == tblSelectEvent) { if (event->data.tblEnter.column == EXCOL_DONE) { MemHandle mex; ExamDBRecord *ex; Boolean done=(TblGetItemInt(event->data.tblSelect.pTable, event->data.tblSelect.row, event->data.tblSelect.column) == 0) ? false : true; UInt16 flags, index=TblGetRowID(event->data.tblSelect.pTable, event->data.tblSelect.row); mex=DmGetRecord(DatabaseGetRefN(DB_MAIN), index); ex = MemHandleLock(mex); flags = ex->flags; if (done) { flags |= EX_FLAG_DONE; } else { flags &= (EX_FLAG_DONE ^ 0xFFFF); } DmWrite(ex, offsetof(ExamDBRecord, flags), &flags, sizeof(flags)); DmReleaseRecord(DatabaseGetRefN(DB_MAIN), index, false); TblMarkRowInvalid(event->data.tblSelect.pTable, event->data.tblSelect.row); TblRedrawTable(event->data.tblSelect.pTable); MemHandleUnlock(mex); } else if (event->data.tblEnter.column == EXCOL_NOTE) { ControlType *ctl=GetObjectPtr(BUTTON_ex_note); // Don't need code twice, just read ctlSelect Event for BUTTON_ex_note CtlHitControl(ctl); } handled=true; } else if (event->eType == ctlRepeatEvent) { // Repeat buttons pressed if( event->data.ctlRepeat.controlID == REPEAT_ex_up ) gExamsOffset -= 1; else gExamsOffset += 1; ExamsTableInit(); TblMarkTableInvalid(GetObjectPtr(TABLE_exams)); TblRedrawTable(GetObjectPtr(TABLE_exams)); } else if (event->eType == keyDownEvent) { // We have a hard button assigned and it was pressed if (TxtCharIsHardKey(event->data.keyDown.modifiers, event->data.keyDown.chr)) { if (! (event->data.keyDown.modifiers & poweredOnKeyMask)) { FrmGotoForm(FORM_main); handled = true; } } } else if (event->eType == menuOpenEvent) { return HandleMenuOpenEvent(event); } else if (event->eType == menuEvent) { // forwarding of menu events return HandleMenuEvent(event->data.menu.itemID); } else if (event->eType == frmOpenEvent) { // initializes and draws the form ControlType *ctl; gExamsOffset=0; ExamsTableInit(); FrmDrawForm (frm); ctl = GetObjectPtr(LIST_ex_cat_trigger); CategoryGetName (DatabaseGetRef(), DatabaseGetCat(), gCategoryName); CategorySetTriggerLabel (ctl, gCategoryName); handled = true; } else if (event->eType == frmUpdateEvent) { // redraws the form if needed gExamsOffset=0; ExamsTableInit(); FrmDrawForm(frm); handled = false; } else if (event->eType == frmCloseEvent) { // this is done if form is closed // TblEraseTable(GetObjectPtr(TABLE_exams)); // ExamsFormFree(); FrmEraseForm(frm); } return (handled); }
/* ** TrackXferDone */ static void TrackXferDone(DynamicButtonType* btn) { RectangleType bounds[5], frame, popFrame, popShadowFrame; Boolean penDown, on_button; Int16 x, y, clicked_on = 0; Int16 state = 1; Int16 i = 0; WinHandle offscreenH = NULL; FormType* frm = FrmGetActiveForm(); const UInt16 listIdx = FrmGetObjectIndex(frm, XferDoneList); ListType* list = FrmGetObjectPtr(frm, listIdx); UInt16 width = 0, choices = 0; Err err = errNone; Char str[48]; Int16 n = 0; /* Save the old drawing context */ WinPushDrawState(); /* This should match the XferDoneButton bounds */ FrmGetObjectBounds(frm, FrmGetObjectIndex(frm, btn->id), &bounds[0]); /* Invert the done button */ SelectAndDrawButton(btn, true); SndPlaySystemSound(sndClick); /* Set the status of each menu pick */ for (; i < 4; i++) d.xfer.status[i] = 0x00; if (xferGotoIsAlways) d.xfer.status[0] = TRACKXFERDONE_ALWAYS; else if (xferGotoIsNever) d.xfer.status[0] = TRACKXFERDONE_NEVER; else if (p.flags&PFLAGS_XFER_GOTO) d.xfer.status[0] = TRACKXFERDONE_CHECKED; if (xferCompleteIsAlways) d.xfer.status[1] = TRACKXFERDONE_ALWAYS; else if (xferCompleteIsNever) d.xfer.status[1] = TRACKXFERDONE_NEVER; else if (d.xfer.complete) d.xfer.status[1] = TRACKXFERDONE_CHECKED; if (!d.linker_available) d.xfer.status[2] = TRACKXFERDONE_NEVER; else if (p.flags&PFLAGS_XFER_BACKLINK) d.xfer.status[2] = TRACKXFERDONE_CHECKED; if (p.flags&PFLAGS_XFER_DELETE) d.xfer.status[3] = TRACKXFERDONE_CHECKED; for (i = 0; i < 4; ++i) { if (!(d.xfer.status[i] & TRACKXFERDONE_NEVER)) { d.xfer.choice_map[choices] = i; ++choices; /* calculate list width */ SysCopyStringResource(str, XferMenuOptionsStrings + i); n = FntCharsWidth(str, StrLen(str)); width = Max(width, n); } } LstSetDrawFunction(list, XferDoneListDrawFunc); LstSetListChoices(list, 0, choices); LstSetHeight(list, Min(choices, 10)); FrmGetObjectBounds(frm, listIdx, &frame); frame.topLeft.y = 144 - frame.extent.y - 1; /* -1 to compensate for white border */ frame.extent.x = width + 15 + 6; FrmSetObjectBounds(frm, listIdx, &frame); WinGetFramesRectangle(popupFrame, &frame, &popFrame); WinGetFramesRectangle(rectangleFrame, &popFrame, &popShadowFrame); for (i = 0; i < choices; ++i) RctSetRectangle(&bounds[i+1], frame.topLeft.x, frame.topLeft.y + 10 * i, frame.extent.x, 10); /* Save the bits of the whole menu */ offscreenH = WinSaveBits(&popShadowFrame, &err); if (err) abort(); /* None selected */ LstSetSelection(list, -1); FrmShowObject(frm, listIdx); WinEraseRectangle(&popShadowFrame, 0); LstDrawList(list); WinEraseRectangleFrame(rectangleFrame, &frame); WinDrawRectangleFrame(popupFrame, &frame); do { EvtGetPen(&x, &y, &penDown); if (!state || !RctPtInRectangle(x, y, &bounds[state-1])) { on_button = false; for (i = 1; i <= choices + 1; i++) { if ((state != i) && RctPtInRectangle(x, y, &bounds[i-1])) { /* Invert the new state */ LstSetSelection(list, i - 2); LstDrawList(list); WinEraseRectangleFrame(rectangleFrame, &frame); WinDrawRectangleFrame(popupFrame, &frame); SelectAndDrawButton(btn, i == 1); state = i; on_button = true; } } if (state && !on_button) { /* Moved off the current button */ LstSetSelection(list, -1); LstDrawList(list); WinEraseRectangleFrame(rectangleFrame, &frame); WinDrawRectangleFrame(popupFrame, &frame); if (state == 1) SelectAndDrawButton(btn, false); state = 0; } } } while (penDown); FrmHideObject(frm, listIdx); LstEraseList(list); /* Restore the framed rect */ WinRestoreBits(offscreenH, popShadowFrame.topLeft.x, popShadowFrame.topLeft.y); /* Unselect the button */ SelectAndDrawButton(btn, false); /* Finish up if we just tapped the button */ if (RctPtInRectangle(x, y, &bounds[0])) { FinishXferMode(); /* Restore the old draw state */ WinPopDrawState(); return; } /* Change the setting for goto or delete */ for (i = 1; i <= choices; i++) { if (RctPtInRectangle(x, y, &bounds[i])) { clicked_on = i; break; } } if (clicked_on) clicked_on = d.xfer.choice_map[clicked_on-1] + 1; switch (clicked_on) { case 1: /* Goto */ if (d.xfer.status[0] & TRACKXFERDONE_CHECKED) p.flags &= ~PFLAGS_XFER_GOTO; else if (!d.xfer.status[0]) p.flags |= PFLAGS_XFER_GOTO; break; case 2: /* Complete */ if (d.xfer.status[1] & TRACKXFERDONE_CHECKED) d.xfer.complete = false; else if (!d.xfer.status[1]) d.xfer.complete = true; break; case 3: /* BackLink */ if (d.xfer.status[2] & TRACKXFERDONE_CHECKED) p.flags &= ~PFLAGS_XFER_BACKLINK; else if (!d.xfer.status[2]) { p.flags |= PFLAGS_XFER_BACKLINK; p.flags &= ~PFLAGS_XFER_DELETE; /* No delete if backlink */ } break; case 4: /* Delete */ if (d.xfer.status[3] & TRACKXFERDONE_CHECKED) p.flags &= ~PFLAGS_XFER_DELETE; else if (!d.xfer.status[3]) { p.flags |= PFLAGS_XFER_DELETE; p.flags &= ~PFLAGS_XFER_BACKLINK; /* No backlink if delete */ } break; } /* Click and redraw the button */ if (clicked_on) { DrawXferDoneButton(btn); DynBtnDraw(btn); if (d.xfer.status[clicked_on-1] & TRACKXFERDONE_ALWAYS) SndPlaySystemSound(sndWarning); else SndPlaySystemSound(sndClick); } /* Restore the old draw state */ WinPopDrawState(); }
/***************************************************************************** * Function: GadgetHintTap * * Description: Handles penDown events (taps) on the hint gadget *****************************************************************************/ void GadgetHintTap(FormGadgetType *pGadget, EventType *event) { //you may find it useful to track if they //lift the pen still within the boundaries of the gadget Boolean isPenDown = true; Int16 newPointX, newPointY, startPointX, startPointY; UInt16 index; RectangleType bounds, rect; Char noteSymb[2] = { GADGET_NOTESYMBOL, 0 }; FontID oldFont; Boolean drawn=false; IndexedColorType curForeColor, curBackColor, curTextColor; // This is just needed since we do not want to access internal structure // data directly in FormGadgetType (need rect field below) index = TNGetObjectIndexFromPtr(FrmGetActiveForm(), pGadget); FrmGetObjectBounds(FrmGetActiveForm(), index, &bounds); oldFont = FntSetFont(symbolFont); RctSetRectangle(&rect, bounds.topLeft.x+1, // +1 for border bounds.topLeft.y+1, // Put VALUE BELOW here.... +top+1 removed because of own Gadget bounds.extent.x-3, bounds.extent.y - 3); // -4 for bottom border RctSetRectangle(&rect, rect.topLeft.x+rect.extent.x-8, rect.topLeft.y+rect.extent.y-12, FntLineWidth(noteSymb, 1), FntLineHeight()); //track the pen down event EvtGetPen(&newPointX, &newPointY, &isPenDown); startPointX = newPointX; startPointY = newPointY; while (isPenDown){ EvtGetPen(&newPointX, &newPointY, &isPenDown); if (gHintNote) { if (! drawn && RctPtInRectangle(newPointX, newPointY, &rect)) { curForeColor = WinSetForeColor(UIColorGetTableEntryIndex(UIObjectSelectedForeground)); curBackColor = WinSetBackColor(UIColorGetTableEntryIndex(UIObjectSelectedFill)); curTextColor = WinSetTextColor(UIColorGetTableEntryIndex(UIObjectSelectedForeground)); TNDrawCharsToFitWidth(noteSymb, &rect); WinSetForeColor(curForeColor); WinSetForeColor(curBackColor); WinSetForeColor(curTextColor); drawn = true; } else if (drawn && ! RctPtInRectangle(newPointX, newPointY, &rect)) { curForeColor = WinSetForeColor(UIColorGetTableEntryIndex(UIObjectForeground)); curBackColor = WinSetBackColor(UIColorGetTableEntryIndex(UIObjectFill)); curTextColor = WinSetTextColor(UIColorGetTableEntryIndex(UIObjectForeground)); TNDrawCharsToFitWidth(noteSymb, &rect); WinSetForeColor(curForeColor); WinSetForeColor(curBackColor); WinSetForeColor(curTextColor); drawn = false; } } } FntSetFont(oldFont); if (gHintNote && RctPtInRectangle(newPointX, newPointY, &rect)) { NoteSet(GadgetGetHintTimeIndex(), FORM_main); FrmPopupForm(NewNoteView); } // else outside gadget bounds -> do nothing }
/***************************************************************************** * Function: GadgetTap * * Description: Handles penDown events (taps) on the gadget *****************************************************************************/ void GadgetTap(FormGadgetType *pGadget, EventType *event) { //you may find it useful to track if they //lift the pen still within the boundaries of the gadget Boolean isPenDown = true; Int16 newPointX, newPointY, startPointX, startPointY; UInt16 index; RectangleType bounds; // This is just needed since we do not want to access internal structure // data directly in FormGadgetType (need rect field below) index = TNGetObjectIndexFromPtr(FrmGetActiveForm(), pGadget); FrmGetObjectBounds(FrmGetActiveForm(), index, &bounds); //track the pen down event EvtGetPen(&newPointX, &newPointY, &isPenDown); startPointX = newPointX; startPointY = newPointY; while (isPenDown){ EvtGetPen(&newPointX, &newPointY, &isPenDown); } if (RctPtInRectangle(newPointX, newPointY, &bounds)) { /* the pen up was also in the gadget This can mean two things: 1) we got a strike command 2) a field was tapped */ RectangleType topRight, bottomRight; Boolean found=false, foundTime=false; MemHandle m; TimeDBRecord *t; UInt16 index=0, wantCourse=0, tmp3_4th=0; GadgetTimeListType *gtl; TNlist *tmpl; /* Check for stroke commands */ tmp3_4th = (3 * bounds.extent.x) / 4; RctSetRectangle(&topRight, bounds.topLeft.x+ tmp3_4th, bounds.topLeft.y, bounds.extent.x - tmp3_4th, bounds.extent.y/2 ); RctSetRectangle(&bottomRight, bounds.topLeft.x + tmp3_4th, bounds.topLeft.y + (bounds.extent.y/2), bounds.extent.x - tmp3_4th, bounds.extent.y / 2 ); if (RctPtInRectangle(startPointX, startPointY, &bottomRight) && RctPtInRectangle(newPointX, newPointY, &topRight) ) { // Stroke Command: BACK GadgetDrawStep(winUp); return; } else if (RctPtInRectangle(startPointX, startPointY, &topRight) && RctPtInRectangle(newPointX, newPointY, &bottomRight) ) { // Stroke Command: NEXT GadgetDrawStep(winDown); return; } tmpl = gGadgetTimeList; while (tmpl != NULL) { gtl = (GadgetTimeListType *)tmpl->data; if (RctPtInRectangle(newPointX, newPointY, &(gtl->rect))) { m = DmQueryRecord(DatabaseGetRef(), gtl->index); if (m) { // mt may be null, for example if next is drawn after delete! t = (TimeDBRecord *)MemHandleLock(m); // we got a match wantCourse = t->course; gTimeIndex = gtl->index; foundTime = true; MemHandleUnlock(m); } } tmpl = tmpl->next; } // Search for the clicked time if (foundTime) { index = 0; while(! found && ((m = DmQueryNextInCategory(DatabaseGetRef(), &index, DatabaseGetCat())) != NULL)) { Char *s = (Char *)MemHandleLock(m); if (s[0] == TYPE_COURSE) { CourseDBRecord c; UnpackCourse(&c, s); if (c.id == wantCourse) { SndPlaySystemSound(sndClick); gCourseIndex = index; found=true; } } MemHandleUnlock(m); index += 1; } } if (found && foundTime) { GadgetDrawHintCurrent(); } else { SndPlaySystemSound(sndError); } } // else outside gadget bounds -> do nothing }