this is close enough
This commit is contained in:
parent
329921ff32
commit
427ac1368f
193
main.c
193
main.c
|
@ -63,9 +63,24 @@ struct Screen *screen;
|
||||||
struct Window *window;
|
struct Window *window;
|
||||||
struct Gadget *windowGadgets;
|
struct Gadget *windowGadgets;
|
||||||
|
|
||||||
//struct NewWindow aboutWindowLayout = { };
|
#define ABOUT_WINDOW_WIDTH (240)
|
||||||
struct Window *aboutWindow;
|
#define ABOUT_WINDOW_HEIGHT (50)
|
||||||
struct Gadget *aboutWindowGadgets;
|
|
||||||
|
struct NewWindow aboutWindowLayout = {
|
||||||
|
40, 40,
|
||||||
|
ABOUT_WINDOW_WIDTH, ABOUT_WINDOW_HEIGHT,
|
||||||
|
0, 1,
|
||||||
|
IDCMP_REFRESHWINDOW | IDCMP_CLOSEWINDOW | BUTTONIDCMP,
|
||||||
|
WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET | WFLG_ACTIVATE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
"About Pizza Timer",
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
ABOUT_WINDOW_WIDTH, ABOUT_WINDOW_HEIGHT,
|
||||||
|
ABOUT_WINDOW_WIDTH, ABOUT_WINDOW_HEIGHT,
|
||||||
|
WBENCHSCREEN
|
||||||
|
};
|
||||||
|
|
||||||
// Fonts!
|
// Fonts!
|
||||||
struct TextAttr Topaz80 = { "topaz.font", 8, 0, 0 };
|
struct TextAttr Topaz80 = { "topaz.font", 8, 0, 0 };
|
||||||
|
@ -88,6 +103,11 @@ struct Gadget *timerGadget, *hourSlider, *minuteSlider, *secondSlider;
|
||||||
|
|
||||||
// gadtools menus
|
// gadtools menus
|
||||||
// https://wiki.amigaos.net/wiki/GadTools_Menus
|
// https://wiki.amigaos.net/wiki/GadTools_Menus
|
||||||
|
|
||||||
|
// Why the special struct, constants and struct instantiation?
|
||||||
|
// Because this way, when we get a menu message from Intuition,
|
||||||
|
// we can look up the menu item selected by ID, rather than
|
||||||
|
// looking it up by position in the menu tree structure.
|
||||||
struct MenuData {
|
struct MenuData {
|
||||||
int id;
|
int id;
|
||||||
};
|
};
|
||||||
|
@ -118,6 +138,8 @@ struct timeval currentSystemTime;
|
||||||
// get that bell
|
// get that bell
|
||||||
#define BELL_FILENAME "bell.8svx"
|
#define BELL_FILENAME "bell.8svx"
|
||||||
|
|
||||||
|
APTR bellSound = NULL;
|
||||||
|
|
||||||
// our business logic
|
// our business logic
|
||||||
// for how long should I cook this pizza?
|
// for how long should I cook this pizza?
|
||||||
unsigned int uiHours = 0;
|
unsigned int uiHours = 0;
|
||||||
|
@ -229,10 +251,8 @@ struct Gadget *buildUI(void) {
|
||||||
currentGadget = CreateContext(&glist);
|
currentGadget = CreateContext(&glist);
|
||||||
|
|
||||||
ng.ng_LeftEdge = WINDOW_CHROME_WIDTH;
|
ng.ng_LeftEdge = WINDOW_CHROME_WIDTH;
|
||||||
// TODO: constantize these
|
|
||||||
ng.ng_TopEdge = 11;
|
ng.ng_TopEdge = 11;
|
||||||
ng.ng_Height = 12;
|
ng.ng_Height = 12;
|
||||||
|
|
||||||
ng.ng_Width = 0;
|
ng.ng_Width = 0;
|
||||||
ng.ng_GadgetText = NULL;
|
ng.ng_GadgetText = NULL;
|
||||||
ng.ng_TextAttr = &Topaz80;
|
ng.ng_TextAttr = &Topaz80;
|
||||||
|
@ -258,6 +278,7 @@ struct Gadget *buildUI(void) {
|
||||||
ng.ng_TextAttr = &Topaz80;
|
ng.ng_TextAttr = &Topaz80;
|
||||||
ng.ng_Height = 12;
|
ng.ng_Height = 12;
|
||||||
|
|
||||||
|
// start/stop button
|
||||||
ng.ng_Width = (WINDOW_WIDTH - WINDOW_CHROME_WIDTH * 2) / 2;
|
ng.ng_Width = (WINDOW_WIDTH - WINDOW_CHROME_WIDTH * 2) / 2;
|
||||||
ng.ng_TopEdge += 18;
|
ng.ng_TopEdge += 18;
|
||||||
if (timerIsRunning) {
|
if (timerIsRunning) {
|
||||||
|
@ -276,6 +297,7 @@ struct Gadget *buildUI(void) {
|
||||||
TAG_END
|
TAG_END
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// reset button
|
||||||
ng.ng_LeftEdge += (WINDOW_WIDTH - WINDOW_CHROME_WIDTH * 2) / 2;
|
ng.ng_LeftEdge += (WINDOW_WIDTH - WINDOW_CHROME_WIDTH * 2) / 2;
|
||||||
ng.ng_GadgetText = "_Reset";
|
ng.ng_GadgetText = "_Reset";
|
||||||
ng.ng_GadgetID = RESET_BUTTON_ID;
|
ng.ng_GadgetID = RESET_BUTTON_ID;
|
||||||
|
@ -289,6 +311,7 @@ struct Gadget *buildUI(void) {
|
||||||
TAG_END
|
TAG_END
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// hours slider
|
||||||
ng.ng_LeftEdge = 85;
|
ng.ng_LeftEdge = 85;
|
||||||
ng.ng_Width = (WINDOW_WIDTH - WINDOW_CHROME_WIDTH * 2) - 85 + 4;
|
ng.ng_Width = (WINDOW_WIDTH - WINDOW_CHROME_WIDTH * 2) - 85 + 4;
|
||||||
ng.ng_TopEdge += 12;
|
ng.ng_TopEdge += 12;
|
||||||
|
@ -314,6 +337,7 @@ struct Gadget *buildUI(void) {
|
||||||
TAG_END
|
TAG_END
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// minutes slider
|
||||||
ng.ng_TopEdge += 12;
|
ng.ng_TopEdge += 12;
|
||||||
ng.ng_GadgetText = "Mins: ";
|
ng.ng_GadgetText = "Mins: ";
|
||||||
ng.ng_GadgetID = MINUTES_SLIDER_ID;
|
ng.ng_GadgetID = MINUTES_SLIDER_ID;
|
||||||
|
@ -331,6 +355,7 @@ struct Gadget *buildUI(void) {
|
||||||
TAG_END
|
TAG_END
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// seconds slider
|
||||||
ng.ng_TopEdge += 12;
|
ng.ng_TopEdge += 12;
|
||||||
ng.ng_GadgetText = "Secs: ";
|
ng.ng_GadgetText = "Secs: ";
|
||||||
ng.ng_GadgetID = SECONDS_SLIDER_ID;
|
ng.ng_GadgetID = SECONDS_SLIDER_ID;
|
||||||
|
@ -351,6 +376,9 @@ struct Gadget *buildUI(void) {
|
||||||
return glist;
|
return glist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the text of the timer and redraw the necessary gadgets.
|
||||||
|
*/
|
||||||
void setTimerText(void) {
|
void setTimerText(void) {
|
||||||
// Only change the timer widget text if the time is different
|
// Only change the timer widget text if the time is different
|
||||||
// from the last render. This prevents unnecessary renders and potential
|
// from the last render. This prevents unnecessary renders and potential
|
||||||
|
@ -422,8 +450,6 @@ void clearUI(void) {
|
||||||
void handleToggleTimer(void) {
|
void handleToggleTimer(void) {
|
||||||
timerIsRunning = !timerIsRunning;
|
timerIsRunning = !timerIsRunning;
|
||||||
|
|
||||||
// TODO: don't reset the timer when it's stopped/started
|
|
||||||
|
|
||||||
if (timerIsRunning) {
|
if (timerIsRunning) {
|
||||||
// http://amigadev.elowar.com/read/ADCD_2.1/Includes_and_Autodocs_2._guide/node04FA.html
|
// http://amigadev.elowar.com/read/ADCD_2.1/Includes_and_Autodocs_2._guide/node04FA.html
|
||||||
GetSysTime(¤tSystemTime);
|
GetSysTime(¤tSystemTime);
|
||||||
|
@ -441,9 +467,12 @@ void handleToggleTimer(void) {
|
||||||
|
|
||||||
timerStarted = TRUE;
|
timerStarted = TRUE;
|
||||||
|
|
||||||
// start the async timer
|
// start the timer
|
||||||
startTimer();
|
startTimer();
|
||||||
} else {
|
} else {
|
||||||
|
// put the sliders back.
|
||||||
|
// it causes a lot of UI flashing to update these as the timer runs,
|
||||||
|
// so only do it once we stop the timer.
|
||||||
GT_SetGadgetAttrs(
|
GT_SetGadgetAttrs(
|
||||||
hourSlider,
|
hourSlider,
|
||||||
window,
|
window,
|
||||||
|
@ -487,6 +516,93 @@ void handleResetTimer(void) {
|
||||||
clearUI();
|
clearUI();
|
||||||
renderUI();
|
renderUI();
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// To keep this simple, the about window will block
|
||||||
|
int openAboutWindow(void) {
|
||||||
|
struct Window *aboutWindow;
|
||||||
|
struct NewGadget ng;
|
||||||
|
struct Gadget *currentGadget;
|
||||||
|
struct Gadget *glist;
|
||||||
|
struct IntuiMessage *iMessage;
|
||||||
|
|
||||||
|
ULONG windowSignal;
|
||||||
|
BOOL closeAbout = FALSE;
|
||||||
|
aboutWindow = OpenWindow(&aboutWindowLayout);
|
||||||
|
|
||||||
|
if (!aboutWindow) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentGadget = CreateContext(&glist);
|
||||||
|
|
||||||
|
ng.ng_LeftEdge = WINDOW_CHROME_WIDTH + 4;
|
||||||
|
ng.ng_TopEdge = 15;
|
||||||
|
ng.ng_Height = 10;
|
||||||
|
ng.ng_Width = 0;
|
||||||
|
ng.ng_GadgetText = NULL;
|
||||||
|
ng.ng_TextAttr = &Topaz80;
|
||||||
|
ng.ng_VisualInfo = visualInfo;
|
||||||
|
|
||||||
|
ng.ng_GadgetID = NULL;
|
||||||
|
ng.ng_Flags = PLACETEXT_IN;
|
||||||
|
|
||||||
|
currentGadget = CreateGadget(
|
||||||
|
TEXT_KIND,
|
||||||
|
currentGadget,
|
||||||
|
&ng,
|
||||||
|
GTTX_Text, "Topaz's Pizza Timer",
|
||||||
|
GTTX_CopyText, TRUE,
|
||||||
|
TAG_DONE
|
||||||
|
);
|
||||||
|
|
||||||
|
ng.ng_TopEdge += 10;
|
||||||
|
currentGadget = CreateGadget(
|
||||||
|
TEXT_KIND,
|
||||||
|
currentGadget,
|
||||||
|
&ng,
|
||||||
|
GTTX_Text, "By John Bintz",
|
||||||
|
GTTX_CopyText, TRUE,
|
||||||
|
TAG_DONE
|
||||||
|
);
|
||||||
|
|
||||||
|
ng.ng_TopEdge += 10;
|
||||||
|
currentGadget = CreateGadget(
|
||||||
|
TEXT_KIND,
|
||||||
|
currentGadget,
|
||||||
|
&ng,
|
||||||
|
GTTX_Text, "theindustriousrabbit.com",
|
||||||
|
GTTX_CopyText, TRUE,
|
||||||
|
TAG_DONE
|
||||||
|
);
|
||||||
|
|
||||||
|
AddGList(aboutWindow, glist, -1, -1, NULL);
|
||||||
|
RefreshGList(glist, aboutWindow, NULL, -1);
|
||||||
|
GT_RefreshWindow(aboutWindow, NULL);
|
||||||
|
|
||||||
|
windowSignal = 1L << aboutWindow->UserPort->mp_SigBit;
|
||||||
|
|
||||||
|
while (!closeAbout) {
|
||||||
|
Wait(windowSignal);
|
||||||
|
|
||||||
|
while (!closeAbout && (iMessage = GT_GetIMsg(aboutWindow->UserPort))) {
|
||||||
|
switch (iMessage->Class) {
|
||||||
|
case IDCMP_CLOSEWINDOW:
|
||||||
|
closeAbout = TRUE;
|
||||||
|
break;
|
||||||
|
case IDCMP_REFRESHWINDOW:
|
||||||
|
GT_BeginRefresh(window);
|
||||||
|
GT_EndRefresh(window, TRUE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveGList(aboutWindow, glist, -1);
|
||||||
|
FreeGadgets(glist);
|
||||||
|
CloseWindow(aboutWindow);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a single Intuition message.
|
* Process a single Intuition message.
|
||||||
|
@ -514,8 +630,8 @@ void handleIntuitionMessage(struct IntuiMessage *iMessage) {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// We picked a menu item.
|
// We picked a menu item.
|
||||||
case IDCMP_MENUPICK:
|
case IDCMP_MENUPICK:
|
||||||
// https://en.wikibooks.org/wiki/Aros/Developer/Docs/Libraries/GadTools
|
// https://en.wikibooks.org/wiki/Aros/Developer/Docs/Libraries/GadTools
|
||||||
|
@ -526,11 +642,20 @@ void handleIntuitionMessage(struct IntuiMessage *iMessage) {
|
||||||
switch (menuData->id) {
|
switch (menuData->id) {
|
||||||
// I originally tried to use MENU_QUIT.id here
|
// I originally tried to use MENU_QUIT.id here
|
||||||
// https://stackoverflow.com/questions/14069737/switch-case-error-case-label-does-not-reduce-to-an-integer-constant
|
// https://stackoverflow.com/questions/14069737/switch-case-error-case-label-does-not-reduce-to-an-integer-constant
|
||||||
|
// This is why there's a bunch more overhead for building
|
||||||
|
// the menu userdata.
|
||||||
case MENU_QUIT_ID:
|
case MENU_QUIT_ID:
|
||||||
terminated = TRUE;
|
terminated = TRUE;
|
||||||
break;
|
break;
|
||||||
|
case MENU_ABOUT_ID:
|
||||||
|
// yes, this blocks, deal with it
|
||||||
|
// it also returns non-zero if something goes wrong.
|
||||||
|
// in that case, kill the program
|
||||||
|
if (openAboutWindow()) terminated = TRUE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// We've moved the mouse. In slider gadget talk, we've changed
|
// We've moved the mouse. In slider gadget talk, we've changed
|
||||||
// the value of the slider.
|
// the value of the slider.
|
||||||
case IDCMP_MOUSEMOVE:
|
case IDCMP_MOUSEMOVE:
|
||||||
|
@ -554,8 +679,8 @@ void handleIntuitionMessage(struct IntuiMessage *iMessage) {
|
||||||
if (rerenderTimer) setTimerText();
|
if (rerenderTimer) setTimerText();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// bye bye
|
|
||||||
case IDCMP_CLOSEWINDOW:
|
case IDCMP_CLOSEWINDOW:
|
||||||
|
// bye bye
|
||||||
terminated = TRUE;
|
terminated = TRUE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -568,12 +693,15 @@ void handleIntuitionMessage(struct IntuiMessage *iMessage) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void endTimer(void) {
|
|
||||||
// TODO: play an included IFF 8SVX sound
|
/**
|
||||||
APTR bellSound = NULL;
|
* Start playing a bell sound, and start a timer to tear down
|
||||||
|
* the bell data once it's done.
|
||||||
|
*/
|
||||||
|
void startBellSound(void) {
|
||||||
struct dtTrigger myTrigger;
|
struct dtTrigger myTrigger;
|
||||||
struct MsgPort *TimerPort;
|
struct MsgPort *TimerPort;
|
||||||
ULONG soundPlayResult, timerSignal;
|
ULONG soundPlayResult;
|
||||||
|
|
||||||
if (bellSound = NewDTObject(BELL_FILENAME, DTA_GroupID, GID_SOUND, TAG_END)) {
|
if (bellSound = NewDTObject(BELL_FILENAME, DTA_GroupID, GID_SOUND, TAG_END)) {
|
||||||
myTrigger.MethodID = DTM_TRIGGER;
|
myTrigger.MethodID = DTM_TRIGGER;
|
||||||
|
@ -592,7 +720,30 @@ void endTimer(void) {
|
||||||
TimerIO->tr_time.tv_micro = 0;
|
TimerIO->tr_time.tv_micro = 0;
|
||||||
SendIO((struct IORequest *)TimerIO);
|
SendIO((struct IORequest *)TimerIO);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tear down the bell once the timer runs out.
|
||||||
|
*/
|
||||||
|
void waitForBellToFinish(void) {
|
||||||
|
struct MsgPort *TimerPort;
|
||||||
|
ULONG timerSignal;
|
||||||
|
|
||||||
|
if (bellSound) {
|
||||||
|
TimerPort = TimerIO->tr_node.io_Message.mn_ReplyPort;
|
||||||
|
|
||||||
|
timerSignal = 1L << TimerPort->mp_SigBit;
|
||||||
|
Wait(timerSignal);
|
||||||
|
|
||||||
|
DisposeDTObject(bellSound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the timer running out of time.
|
||||||
|
*/
|
||||||
|
void endTimer(void) {
|
||||||
|
startBellSound();
|
||||||
DisplayBeep(screen);
|
DisplayBeep(screen);
|
||||||
|
|
||||||
uiHours = uiMinutes = uiSeconds = 0;
|
uiHours = uiMinutes = uiSeconds = 0;
|
||||||
|
@ -604,12 +755,7 @@ void endTimer(void) {
|
||||||
clearUI();
|
clearUI();
|
||||||
renderUI();
|
renderUI();
|
||||||
|
|
||||||
if (bellSound) {
|
waitForBellToFinish();
|
||||||
timerSignal = 1L << TimerPort->mp_SigBit;
|
|
||||||
Wait(timerSignal);
|
|
||||||
|
|
||||||
DisposeDTObject(bellSound);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleTimerMessage(void) {
|
void handleTimerMessage(void) {
|
||||||
|
@ -648,7 +794,6 @@ void clearMenu(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// TODO: Menu bar with about menu and change the title to match the time
|
|
||||||
struct IntuiMessage *iMessage;
|
struct IntuiMessage *iMessage;
|
||||||
struct MsgPort *TimerPort;
|
struct MsgPort *TimerPort;
|
||||||
ULONG windowSignal, timerSignal, foundSignals;
|
ULONG windowSignal, timerSignal, foundSignals;
|
||||||
|
@ -671,14 +816,16 @@ int main() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// http://amigadev.elowar.com/read/ADCD_2.1/Includes_and_Autodocs_3._guide/node03F8.html
|
||||||
|
SetWindowTitles(window, (UBYTE *) ~0, "Topaz's Pizza Timer - theindustriousrabbit.com");
|
||||||
|
buildMenu();
|
||||||
|
|
||||||
// these create the bit mask for Wait() to listen to events on
|
// these create the bit mask for Wait() to listen to events on
|
||||||
windowSignal = 1L << window->UserPort->mp_SigBit;
|
windowSignal = 1L << window->UserPort->mp_SigBit;
|
||||||
timerSignal = 1L << TimerPort->mp_SigBit;
|
timerSignal = 1L << TimerPort->mp_SigBit;
|
||||||
|
|
||||||
renderUI();
|
renderUI();
|
||||||
|
|
||||||
buildMenu();
|
|
||||||
|
|
||||||
while (!terminated) {
|
while (!terminated) {
|
||||||
// http://amigadev.elowar.com/read/ADCD_2.1/Libraries_Manual_guide/node02EB.html
|
// http://amigadev.elowar.com/read/ADCD_2.1/Libraries_Manual_guide/node02EB.html
|
||||||
// http://www.amigadev.elowar.com/read/ADCD_2.1/Includes_and_Autodocs_2._guide/node038A.html
|
// http://www.amigadev.elowar.com/read/ADCD_2.1/Includes_and_Autodocs_2._guide/node038A.html
|
||||||
|
|
Loading…
Reference in New Issue