#include // this is the manual for the original intuition stuff. // not much here is different: https://ia801905.us.archive.org/33/items/Amiga_Intuition_Reference_Manaual_1985_Adn-Wesley_Publishing_Company/Amiga_Intuition_Reference_Manaual_1985_Addison-Wesley_Publishing_Company.pdf #include #include #include #include #include #include // gadtools gives a proper set of components for building UIs. // http://amigadev.elowar.com/read/ADCD_2.1/Libraries_Manual_guide/node0278.html #include #include #define WINDOW_WIDTH (240) #define WINDOW_HEIGHT (100) #define WINDOW_TITLE "Topaz Timer" #define WINDOW_CHROME_WIDTH (4) struct NewWindow winlayout = { 20, 20, // x, y WINDOW_WIDTH, WINDOW_HEIGHT, // w, h 0, 1, // detailpen, blockpen, // you have to add the different gadget types you're looking for // http://amigadev.elowar.com/read/ADCD_2.1/Includes_and_Autodocs_2._guide/node0106.html IDCMP_CLOSEWINDOW | BUTTONIDCMP | SLIDERIDCMP, // IDCMP flags WFLG_SMART_REFRESH | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET | WFLG_ACTIVATE, // window flag from Window struct NULL, // FirstGadget NULL, // menu checkmark WINDOW_TITLE, // title NULL, // default screen NULL, // bitmap WINDOW_WIDTH, WINDOW_HEIGHT, // min size WINDOW_WIDTH, WINDOW_HEIGHT, // max size, WBENCHSCREEN // screen where you want the window to open }; struct TextAttr Topaz80 = { "topaz.font", 8, 0, 0 }; // There's no native 16 pixel Topaz font so we'll use // diskfont.library to make one. struct TextAttr Topaz160 = { "topaz.font", 16, 0, 0 }; #define START_STOP_BUTTON_ID 0 #define RESET_BUTTON_ID 1 #define HOURS_SLIDER_ID 2 #define MINUTES_SLIDER_ID 3 #define SECONDS_SLIDER_ID 5 #define TIMER_COUNTDOWN_COUNT 3 struct Window *window; struct TextFont *topaz80Font; struct TextFont *topaz160Font; struct Screen *screen; void *visualInfo; struct Gadget *timerGadget; unsigned int uiHours = 0; unsigned int uiMinutes = 12; unsigned int uiSeconds = 0; unsigned int activeHours; unsigned int activeMinutes; unsigned int activeSeconds; char timerText[9]; BOOL timerIsRunning; struct Device *TimerBase; static struct IORequest timereq; /** * Initialize system stuff. */ int setup() { // http://amigadev.elowar.com/read/ADCD_2.1/Includes_and_Autodocs_3._guide/node0308.html // make sure the font exists on the computer if (NULL == (topaz80Font = OpenFont(&Topaz80))) { return 0; } if (NULL == (topaz160Font = OpenDiskFont(&Topaz160))) { return 0; } if (NULL == (screen = LockPubScreen(NULL))) { return 0; } if (NULL == (visualInfo = GetVisualInfo(screen, TAG_END))) { return 0; } if (0 != (OpenDevice("timer.device", 0, &timereq, 0))) { return 0; } TimerBase = timereq.io_Device; activeHours = uiHours; activeMinutes = uiMinutes; activeSeconds = uiSeconds; return 1; } /** * Tear down system stuff. */ void teardown() { if (visualInfo) FreeVisualInfo(visualInfo); if (screen) UnlockPubScreen(NULL, screen); if (topaz80Font) CloseFont(topaz80Font); if (topaz160Font) CloseFont(topaz160Font); if (timereq.io_Device) CloseDevice(&timereq); } struct Gadget *buildUI() { struct NewGadget ng; struct Gadget *currentGadget; struct Gadget *glist; currentGadget = CreateContext(&glist); ng.ng_LeftEdge = WINDOW_CHROME_WIDTH; // TODO: constantize these ng.ng_TopEdge = 11; ng.ng_Height = 12; ng.ng_Width = 0; ng.ng_GadgetText = NULL; ng.ng_TextAttr = &Topaz80; ng.ng_VisualInfo = visualInfo; // TODO: use constants to indicate which gadget is which ng.ng_GadgetID = NULL; ng.ng_Flags = PLACETEXT_IN; // Timer display ng.ng_Width = WINDOW_WIDTH - WINDOW_CHROME_WIDTH * 2; ng.ng_TextAttr = &Topaz160; ng.ng_Height = 20; timerGadget = currentGadget = CreateGadget( TEXT_KIND, currentGadget, &ng, GTTX_Text, "", GTTX_Justification, GTJ_CENTER, GTTX_Border, TRUE, TAG_END ); ng.ng_TextAttr = &Topaz80; ng.ng_Height = 12; ng.ng_Width = (WINDOW_WIDTH - WINDOW_CHROME_WIDTH * 2) / 2; ng.ng_TopEdge += 18; if (timerIsRunning) { ng.ng_GadgetText = "_Stop"; } else { ng.ng_GadgetText = "_Start"; } ng.ng_GadgetID = START_STOP_BUTTON_ID; currentGadget = CreateGadget( BUTTON_KIND, currentGadget, &ng, GT_Underscore, '_', TAG_END ); ng.ng_LeftEdge += (WINDOW_WIDTH - WINDOW_CHROME_WIDTH * 2) / 2; ng.ng_GadgetText = "_Reset"; ng.ng_GadgetID = RESET_BUTTON_ID; currentGadget = CreateGadget( BUTTON_KIND, currentGadget, &ng, GT_Underscore, '_', GA_Disabled, timerIsRunning, TAG_END ); ng.ng_LeftEdge = 85; ng.ng_Width = (WINDOW_WIDTH - WINDOW_CHROME_WIDTH * 2) - 85 + 4; ng.ng_TopEdge += 12; ng.ng_GadgetText = "Hours: "; ng.ng_Flags = PLACETEXT_LEFT; ng.ng_GadgetID = HOURS_SLIDER_ID; currentGadget = CreateGadget( SLIDER_KIND, currentGadget, &ng, GT_Underscore, '_', GTSL_Min, 0, GTSL_Max, 23, GTSL_Level, uiHours, GTSL_MaxLevelLen, 2, GTSL_LevelFormat, "%2ld", GA_Disabled, timerIsRunning, TAG_END ); ng.ng_TopEdge += 12; ng.ng_GadgetText = "Mins: "; ng.ng_GadgetID = MINUTES_SLIDER_ID; currentGadget = CreateGadget( SLIDER_KIND, currentGadget, &ng, GT_Underscore, '_', GTSL_Min, 0, GTSL_Max, 59, GTSL_Level, uiMinutes, GTSL_MaxLevelLen, 2, GTSL_LevelFormat, "%2ld", GA_Disabled, timerIsRunning, TAG_END ); ng.ng_TopEdge += 12; ng.ng_GadgetText = "Secs: "; ng.ng_GadgetID = SECONDS_SLIDER_ID; currentGadget = CreateGadget( SLIDER_KIND, currentGadget, &ng, GT_Underscore, '_', GTSL_Min, 0, GTSL_Max, 59, GTSL_Level, uiSeconds, GTSL_MaxLevelLen, 2, GTSL_LevelFormat, "%2ld", GA_Disabled, timerIsRunning, TAG_END ); return glist; } void setTimerText() { // TODO: don't rerender if the time hasn't changed sprintf(timerText, "%02d:%02d:%02d", activeHours, activeMinutes, activeSeconds); GT_SetGadgetAttrs( timerGadget, window, NULL, GTTX_Text, &timerText, TAG_DONE ); } int main() { struct Gadget *gad; BOOL terminated = FALSE; BOOL rerenderTimer = FALSE; struct IntuiMessage *iMessage; struct Gadget *targetGadget; struct timeval currentSystemTime; unsigned int timerRerenderCountdown = 0; // timeval tv_secs is ULONG and that will let us have accurate // time counting via timer.device. ULONG timerStartTime, timerDistance, timerBuild; timerIsRunning = FALSE; if (0 == setup()) { teardown(); return 1; } GetSysTime(¤tSystemTime); timerStartTime = currentSystemTime.tv_secs; window = OpenWindow(&winlayout); gad = buildUI(); // use -1 for working with all gadgets AddGList(window, gad, -1, -1, NULL); RefreshGList(gad, window, NULL, -1); GT_RefreshWindow(window, NULL); setTimerText(); // what the fuck, you have to set the labels afterwards? // you know what, it's better if it's explicit rather than the // pointer shit it was trying to do before. //GT_SetGadgetAttrs(one, window, NULL, GTTX_Text, "wow", TAG_DONE); // after doing anything with gadgets, you need to refresh them //RefreshGList(gad, window, NULL, 3); // you son of a bitch, this is what you need printf("sig signal %d\n", window->UserPort->mp_SigBit); while (!terminated) { // what is a userport on a window // 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 //WaitPort(window->UserPort); // but we need a timer // this shoud be responsive enoug Delay(4); if (timerIsRunning) { timerRerenderCountdown += 1; if (timerRerenderCountdown > TIMER_COUNTDOWN_COUNT) { timerRerenderCountdown = 0; GetSysTime(¤tSystemTime); timerDistance = currentSystemTime.tv_secs - timerStartTime; timerBuild = (uiHours * 3600 + uiMinutes * 60 + uiSeconds) - timerDistance; activeHours = timerBuild / 3600; activeMinutes = timerBuild / 60 % 60; activeSeconds = timerBuild % 60; setTimerText(); } } while ((!terminated) && (iMessage = GT_GetIMsg(window->UserPort))) { switch (iMessage->Class) { case IDCMP_GADGETUP: targetGadget = (struct Gadget *)iMessage->IAddress; switch (targetGadget->GadgetID) { case START_STOP_BUTTON_ID: timerIsRunning = !timerIsRunning; if (timerIsRunning) { GetSysTime(¤tSystemTime); timerStartTime = currentSystemTime.tv_secs; timerRerenderCountdown = 0; rerenderTimer = TRUE; } RemoveGList(window, gad, -1); FreeGadgets(gad); gad = buildUI(); AddGList(window, gad, -1, -1, NULL); RefreshGList(gad, window, NULL, -1); GT_RefreshWindow(window, NULL); break; case RESET_BUTTON_ID: rerenderTimer = TRUE; activeHours = uiHours; activeMinutes = uiMinutes; activeSeconds = uiSeconds; break; } break; case IDCMP_MOUSEMOVE: targetGadget = (struct Gadget *)iMessage->IAddress; switch (targetGadget->GadgetID) { case HOURS_SLIDER_ID: activeHours = uiHours = iMessage->Code; rerenderTimer = TRUE; break; case MINUTES_SLIDER_ID: activeMinutes = uiMinutes = iMessage->Code; rerenderTimer = TRUE; break; case SECONDS_SLIDER_ID: activeSeconds = uiSeconds = iMessage->Code; rerenderTimer = TRUE; break; } break; case IDCMP_CLOSEWINDOW: terminated = TRUE; break; case IDCMP_REFRESHWINDOW: GT_BeginRefresh(window); GT_EndRefresh(window, TRUE); break; } if (rerenderTimer) { setTimerText(); rerenderTimer = FALSE; } } } RemoveGList(window, gad, -1); FreeGadgets(gad); if (window) { CloseWindow(window); } teardown(); return 0; }