/* ------------------------------------------------------------------------ System : cc65 cross-development environment Platform : Apple IIe Program : TextSlides (C) Copyright Olivier Guinart 2015. All rights reserved. Description : Apple //e ProDOS 8 Text-based Slideshow Program Written by : Olivier Guinart Date Written : April 2015 Revision : 1.0 First Release (CC65) Date Revised : xxxxx Licence : You may use this program for whatever you wish as long as you agree that Olivier Guinart has no warranty or liability obligations whatsoever from said use. ------------------------------------------------------------------------ */ #ifndef __APPLE2__ #define __APPLE2__ #endif #include #include #include #include #include #include "_file.h" #define iMaxStrLen 256 #define ELLIPSIS "...\0" // Used to truncate the slide title if it's longer than screen width unsigned char XSize, YSize; // Used to store screen size int iSlidesPosition[iMaxStrLen]; // Used to store slides position within Diapos.txt for fseek purposes char strTemp[iMaxStrLen]; // Temp string int ch; // Temp char int iPos; // Temp var that tracks the current line of the slides txt file int iCurrentSlide; // Tracks the current slide being displayed /* 1MHZ timing loop settings - increase for faster machines */ #define YTIME 60L #define XTIME 2L char wait(unsigned duration) { char c = 0; long y, x; while (duration > 0) { for (y = 0; y < YTIME; y++) { for (x = 0; x < XTIME; x++) { if (kbhit()) { c = cgetc(); /* clear keyboard buffer */ while (kbhit())cgetc(); return c; } } } duration--; } return c; } void sound(int duration, int pitch) { char *speaker = (char*) 0xC030; int i, j; char c; for (i = 0; i < duration; i++) { c += *speaker; for (j = 0; j < pitch; j++); } } /* fgets for Apple II text files - read native apple II text files properly! the cc65 version doesn't! Which means that you need to use unix text files unless you roll your own fgets... */ /* Created in Windows, text file lines end with CRLF, chr(13) + chr(10) */ char* __fastcall__ fgets(char* s, unsigned size, register FILE* f) { register char* p = s; unsigned i; int c; if (size == 0) { /* Invalid size */ return (char*)_seterrno(EINVAL); } /* Read input */ i = 0; c = fgetc(f); while (c != EOF && ((char)c != (char)13)) { //printf("'%i' ",c); /* One char more */ *p = c; ++p; ++i; c = fgetc(f); } if (c == EOF) { // printf("DEBUG: in fgets with EOF%c",(char)13); /* Error or EOF */ if ((f->f_flags & _FERROR) != 0 || i == 0) { /* ERROR or EOF on first char */ // printf("DEBUG: in fgets returning %i%c",NULL,(char)13); *p = '\0'; return NULL; } } /* On lit le charactere LF, on l'ignore */ c = fgetc(f); /* Terminate the string */ *p = '\0'; /* Done */ return s; } //////////////////////////////////////////////////////////////////////////////////// /// Repositions the file pointer to line iLine /// iLine line number were the next read will happen /// fp file from which to read the iBullets points //////////////////////////////////////////////////////////////////////////////////// int PositionFilePointer(int iLine, FILE *fp) { int i; // If we are here, it means we need to close the file, re-open it and reposition the pointer to the line #iLine... fclose(fp); /* We test/open the files of slides */ if ((fp = fopen("Diapos.txt", "r")) == NULL) { printf("Files 'Diapos.txt' couldn't be opened. Press a key to exit."); cgetc(); return EXIT_FAILURE; } for (i = 1; i < iLine; i++) { fgets(strTemp, iMaxStrLen, fp); } return EXIT_SUCCESS; } /////////////////////////////////////////////////////////////////////////////// /// Print slide frame /////////////////////////////////////////////////////////////////////////////// void SlideFrame() { /* Set screen colors, hide the cursor */ //textcolor(COLOR_WHITE); //bordercolor(COLOR_BLACK); //bgcolor(COLOR_BLACK); //cursor(0); /* Clear the screen, put cursor in upper left corner */ clrscr(); /* Draw a border around the screen */ /* Top line */ cputc(CH_ULCORNER); chline(XSize - 2); cputc(CH_URCORNER); /* Vertical line, left side */ cvlinexy(0, 1, YSize - 2); /* Bottom line */ cputc(CH_LLCORNER); chline(XSize - 2); cputc(CH_LRCORNER); /* Vertical line, right side */ cvlinexy(XSize - 1, 1, YSize - 2); } /////////////////////////////////////////////////////////////////////////////// /// Slide #0 with title and subtitle of the presentation /// strTitles, 2 strings arrays for title and subtitle /////////////////////////////////////////////////////////////////////////////// void ShowOpeningSlide(char strTitles[2][iMaxStrLen]) { int ilenTitle, ilenSubTitle, iMidX, iMidY; ilenTitle = strlen(strTitles[0]); ilenSubTitle = strlen(strTitles[1]); // If Title and subtitle are empty, no need to even display an opening slides... if ((ilenTitle + ilenSubTitle) > 0) { SlideFrame(); // printf("DEBUG: ilen '%i'%c", ilen, (char)13); // printf("DEBUG: XSize '%i'%c", XSize, (char)13); iMidX = XSize / 2; iMidY = YSize / 2; // printf("DEBUG: iMidX '%i'%c", iMidX, (char)13); // Printing first the frame of the title /* Vertical line, left side (x, y, longueur) */ // cvlinexy(iMidX - 2, 1, 1); /* Ligne horizontale sous le texte */ // chlinexy(iMidX - 1, 2, ilen + 2); /* Vertical line, right side */ // cvlinexy(iMidX + ilen + 1, 1, 1); // Handling the title now, it will print from both right and left sides, animation effect... gotoxy(iMidX - (ilenTitle / 2), iMidY - 4); // -4 to print a little bit above the middle printf("%s", strTitles[0]); gotoxy(iMidX - (ilenSubTitle / 2), iMidY); printf("%s", strTitles[1]); } } /////////////////////////////////////////////////////////////////////////////// /// Reads the slides file and call the ShowOpeningSlide procedure /// strTitles, 2 strings arrays for title and subtitle /// fp the slides text file /////////////////////////////////////////////////////////////////////////////// int OpenAndShowOpeningSlide(char strTitles[2][iMaxStrLen], FILE *fp) { iPos = 0; // iPos will record the current line of the slides txt file iCurrentSlide = 0; PositionFilePointer(iPos, fp); fgets(strTitles[0], iMaxStrLen, fp); iPos++; iSlidesPosition[iCurrentSlide] = iPos; // the opening slide is always on first (and second) line of the slides text file fgets(strTitles[1], iMaxStrLen, fp); iPos++; ShowOpeningSlide(strTitles); return cgetc(); } /////////////////////////////////////////////////////////////////////////////// /// Print slide titles, below top frame line, centered and boxed /// strTitle, the title of the slide read in Main() loop /////////////////////////////////////////////////////////////////////////////// void SlideTitle(char strTitle[iMaxStrLen]) { int i, j, ilen, iMidX; int iMargin = 5; register char* p; ilen = strlen(strTitle); // printf("DEBUG: ilen '%i'%c", ilen, (char)13); // printf("DEBUG: XSize '%i'%c", XSize, (char)13); // We need to test if the title is longer than the screen width + some buffer = 5 // If yes, we truncate with ellipsis... if (ilen >= (XSize - iMargin)) { p = strTitle + XSize - iMargin - strlen(ELLIPSIS); memcpy(p, ELLIPSIS, strlen(ELLIPSIS)); ilen = strlen(strTitle); } iMidX = (XSize - ilen) / 2; // printf("DEBUG: iMidX '%i'%c", iMidX, (char)13); // printf("DEBUG: ilen = %i%c",ilen,(char)13); // Printing first the frame of the title /* Vertical line, left side (x, y, longueur) */ cvlinexy(iMidX - 2, 1, 1); /* Ligne horizontale sous le texte */ chlinexy(iMidX - 1 , 2, ilen + 2); /* Vertical line, right side */ cvlinexy(iMidX + ilen + 1, 1, 1); // Handling the title now, it will print from both right and left sides, animation effect... i = 0; j = ilen - 1; // zero-index string array... while (i <= j) { gotoxy(iMidX + i, 1); printf("%c", strTitle[i]); gotoxy(iMidX + j, 1); printf("%c", strTitle[j]); sound(5, 30); wait(1); i++; j--; } } ///////////////////////////////////////////////////////////////////////////////////// /// Reads bullets from text files and prints them on screen, with margins x = 5, start y = 7 /// iBullets number of bullets/points of the slide /// fp file from which to read the iBullets points ///////////////////////////////////////////////////////////////////////////////////// void SlideBullets(int iBullets, FILE *fp) { const int iHmarge = 5; const int iVmarge = 5; int i; for (i = 0; i < iBullets; i++) { gotoxy(iHmarge, iVmarge + i); fgets(strTemp, iMaxStrLen, fp); printf("%s", strTemp); } } //////////////////////////////////////////////////////////////////////////////////// /// Draws the whole slide /// strTitle, the title of the slide read in Main() loop /// iBullets number of bullets/points of the slide /// fp file from which to read the iBullets points //////////////////////////////////////////////////////////////////////////////////// void TitleAndContentSlide(char strTitle[iMaxStrLen], int iBullets, FILE *fp) { // We draw the frame of the slide SlideFrame(); // We print the slide title SlideTitle(strTitle); // We load and print iBullets bullets from text file fp SlideBullets(iBullets, fp); } //////////////////////////////////////////////////////////////////////////////////// /// Main :) //////////////////////////////////////////////////////////////////////////////////// int main(void) { char strTitles[2][iMaxStrLen]; char strSlideTitle[iMaxStrLen]; int iBullets; FILE *fp; /* We test/open the files of slides */ if ((fp = fopen("Diapos.txt", "r")) == NULL) { printf("Files 'Diapos.txt' couldn't be opened. Press a key to exit."); cgetc(); return EXIT_FAILURE; } videomode(VIDEOMODE_80COL); /* Ask for the screen size */ screensize(&XSize, &YSize); // Slides are read from file // File structure: // 1st line = Presentation title (to be printed in Opening Slide) // 2nd line = Presentation subtitle (to be printed in Opening Slide) // 3rd line = Title of the first slide // 4th line = n number of bullets for that slide // n following lines = bullets of the slide // Repeat with 3rd, 4th and n lines structure for next slides ch = OpenAndShowOpeningSlide(strTitles, fp); // First slide, First line = title... while (fgets(strSlideTitle, iMaxStrLen, fp) != NULL) { // We record the slide position in the slides text file iCurrentSlide++; iPos++; // +1 because of the title // printf("DEBUG: iCurrentSlide='%i' iPos='%i'%c", iCurrentSlide, iPos, (char)13); // cgetc(); iSlidesPosition[iCurrentSlide] = iPos; // We save the line position of the slide title // Second line = Number of bullets in current slide... fgets(strTemp, iMaxStrLen, fp); iPos++; // +1 because of the count of bullets // printf("DEBUG: strTemp '%s'%c", strTemp, (char)13); iBullets = atoi(strTemp); iPos+=iBullets; // And adding the bullets themselves TitleAndContentSlide(strSlideTitle, iBullets, fp); // We pause before going to next slide ch = cgetc(); if (ch == CH_ESC) // If escape key pressed, exit loop { break; } if (ch == CH_CURS_LEFT) // Back to previous slide with left arrow letter (for now) { iCurrentSlide--; if (iCurrentSlide > 0) { iPos = iSlidesPosition[iCurrentSlide]; PositionFilePointer(iPos, fp); // When we entered the loop the first time, we weren't yet on the line, now we are, so // to avoid counting it twice, we decrease it here by one... iPos--; // And same for the slide #... iCurrentSlide--; } else { // we are back to the opening slide // and we keep looping if users keeps pressing left arrow ch = OpenAndShowOpeningSlide(strTitles, fp); while (ch == CH_CURS_LEFT) { ch = cgetc(); }; // but we exit loop if ESC if (ch == CH_ESC) { break; } } } } // Close the file fclose(fp); clrscr(); return EXIT_SUCCESS; }