This is FlashDoc.m in view mode; [Download] [Up]
#import "FlashDoc.h" /* ------------------------------------------------------------------- enum {KEY, RES, NTextViews}; RDR, Inc. Objective-C source file for the class FlashDoc COPYRIGHT (C), 1991, RDR, Inc. ALL RIGHTS RESERVED. Responsible: Approved: RDR:Ernest Prabhakar Date: Rev: 1991-Oct-04 ___ FlashDoc 1. Introduction Implements a Deck of FlashCards on top of the Ordered List. Starts at the end of the deck and works its way down. Difficult words reappear more often. 2. Revision History ___ The starting point. Ernest Prabhakar/1991-Oct-04 3. Source Code ------------------------------------------------------------------- */ /* ------------------------- Import files ------------------------- */ #import <appkit/nextstd.h> #import <objc/hashtable.h> #import <appkit/Matrix.h> #import <appkit/ScrollView.h> #import <appkit/NXSplitView.h> #import <appkit/Text.h> #import <appkit/Font.h> #import <appkit/Panel.h> #import <appkit/ButtonCell.h> /* ------------------------ Classes used ------------------------ */ #import <objc/List.h> #import <appkit/Panel.h> #import "BasicApp.h" /* -------------------------- Defines --------------------------- */ #define ZAlloc(CL) [CL allocFromZone:[self zone]] #define ClassKind(Obj,Class) [Obj isKindOf:[Class class]] #define P_HIGH 104.0 // Cell Size #define P_WIDE 274.0 #define P_MARG 7.0 #define ObjName(S) "Card_" #S #define SetCell(I,T,S) [[[diff cellAt:0:I] setTitle:#T] setAction:@selector(S)] #define SetDiffCell(I,N) SetCell(I,N, was ## N ## :) /* ------------------------- Constants -------------------------- */ /* ---------------------- Class variables ----------------------- */ /* -------------------- Auxiliary Functions --------------------- */ static id getScroll(NXRect *temp, id* tv, const char *font) { id scroll = [[ScrollView alloc] initFrame:temp]; *tv = [[Text allocFromZone:[scroll zone]] initFrame:temp]; [[*tv setMonoFont:NO] setFont:[NXApp defaultFont:font]]; [scroll setDocView:*tv]; [[[scroll setBorderType:NX_BEZEL] setVertScrollerRequired:YES] setBackgroundGray:NX_WHITE]; return scroll; } static void alignText(Text *text, int align) { [[text setAlignment:align] calcLine]; } static void writeToCard(Card *card, id* tv) { int i=2; // Bottom Up NXStream *stream; while(i--) { stream=NXOpenMemory(NULL,0,NX_READWRITE); [tv[i] writeRichText:stream]; [card setStringValueFrom:stream at:i]; NXCloseMemory(stream, NX_FREEBUFFER); [card setIntValue:[tv[i] alignment] at:i]; } } static void setText(id text, NXStream *stream, int align) { if (stream) { [text readRichText:stream]; NXCloseMemory(stream, NX_SAVEBUFFER); alignText(text, align); } else { [text setText:"<Blank>"]; } } static void readFromCard(Card *card, id* tv) { int i=2; while(i--) setText(tv[i],[card stringStreamAt:i],[card intValueAt:i]); } static Text *newText(int half) { Text *text; NXRect myRect; NXSetRect(&myRect, half*P_WIDE, 0.0, P_WIDE, P_HIGH ); text = [[[Text alloc] initFrame:&myRect] setVertResizable:YES]; [text setMarginLeft:P_MARG right:P_MARG top:P_MARG bottom:P_MARG]; [text setMonoFont:NO]; return text; } static id wrapViews(id aText, id bText, NXCoord *height) { static NXRect myFrame; NXRect aFrame, bFrame; [[aText sizeToFit] calcLine]; [aText getFrame:&aFrame]; [[bText sizeToFit] calcLine]; [bText getFrame:&bFrame]; *height = MAX(NX_HEIGHT(&aFrame), NX_HEIGHT(&bFrame)); NXSetRect(&myFrame, 0.0, 0.0, 2*P_WIDE, *height); return [[[[View allocFromZone:[aText zone]] initFrame:&myFrame] addSubview:aText] addSubview:bText]; } /*==================================================================== Implementation of class FlashDoc ====================================================================*/ @implementation FlashDoc : Document { BOOL viewMode; BOOL cardChanged; id textView[NTextViews]; id rand; id reveal; id diff; id markCount; unsigned int current; } /*==================================================================== Initialize Methods ====================================================================*/ /*-------------------------------------------------------------------- |-getWindow| * set textViews and their delegates; orders the window front; Returns self. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -getWindow { static const char * const defaultName[] = {"KeyFont", "NXFont"}; static NXRect SplitRect; int kr; [self getWindowFromNib:"Card.nib"]; rand = [Random new]; current = [contents count]; viewMode = YES; if (!current) [self switchViewMode:self]; [view setDelegate:self]; [view getBounds:&SplitRect]; NX_HEIGHT(&SplitRect) /= 3; for(kr=0; kr < NTextViews; kr++) { id scroll = getScroll(&SplitRect, &textView[kr], defaultName[kr]); [view addSubview:scroll]; [textView[kr] setDelegate:self]; } [[view adjustSubviews] update]; view = nil; [self nextCard]; return self; } /*==================================================================== Provide Card ====================================================================*/ /*-------------------------------------------------------------------- |-nextCard| Go to next card. If at end, wrap or generate a new blank card. Does NOT handle synchronization. Returns self. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -nextCard { cardChanged = NO; if (!current) { if (!viewMode) [self addCard]; else Notify("Deck", "End of Deck. Starting over."); current = [contents count]; } --current; return [self showCard]; } /*-------------------------------------------------------------------- |-addCard| Returns self. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -addCard { id card = [[ZAlloc(Card) initCount:2] setIntValue:NX_CENTERED at:KEY]; int i = NTextViews; while (i--) [card setStringValue:" " at:i]; cardChanged = YES; [contents addObject:card]; Notify("Deck", "New Card added at beginning of Deck."); return self; } /*-------------------------------------------------------------------- |-(BOOL)sync| Make sure what is on the screen is the same as what is on the card. Sync as needed. YES if not changed or synchronized, NO if aborted. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -(BOOL)sync { if (cardChanged) { switch(NXRunAlertPanel("Edit", "Card modified. Record changes?", "OK", "Discard Changes", NULL)) { case NX_ALERTALTERNATE: return NO; default: [self saveCard]; return YES; } } return YES; } /*==================================================================== Card Display Methods ====================================================================*/ /*-------------------------------------------------------------------- |-showCard| * Display card. Blacken RES if in View Mode Returns self. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -showCard { if ([reveal state] && viewMode) [reveal performClick:self]; readFromCard([contents objectAt:current], textView); [markCount setIntValue:current]; [window makeFirstResponder:window]; [[window contentView] update]; return self; } /*-------------------------------------------------------------------- |-saveCard| Replace current with the contents of the view. Returns self. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -saveCard { writeToCard([contents objectAt:current],textView); cardChanged = NO; [window setDocEdited:YES]; return self; } /*==================================================================== State Variables ====================================================================*/ /*-------------------------------------------------------------------- |-view| * Returns the TextView which is first responder; * Returns nil if firstResponder is not Text. Returns self. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -view { view = [window firstResponder]; if (!ClassKind(view, [Text class])) view = nil; return view; } /*-------------------------------------------------------------------- |-(BOOL) viewMode;| * Returns the viewMode associated with this document. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -(BOOL) viewMode; { return viewMode; } /*-------------------------------------------------------------------- |-setViewMode:(BOOL)newMode| * Change between viewing and editing mode Returns nil if can't change, otherwise self. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -setViewMode:(BOOL)newMode { viewMode = newMode; [self sync]; if (viewMode) { [self cover:self]; [[reveal setTitle:"Reveal"] setAction:@selector(reveal:)]; [[[reveal setAltTitle:"Cover"] setType:NX_TOGGLE] setState:0]; SetDiffCell(0,Easy); SetDiffCell(1,Fair); SetDiffCell(2,Hard); } else { [self reveal:self]; [[reveal setTitle:"Next"] setAction:@selector(next:)]; [reveal setType:NX_MOMENTARYPUSH]; SetCell(0,Revert,revertCard:); SetCell(1,Modify,modify:); SetCell(2,Delete,delete:); // [[window makeFirstResponder:textView[KEY]] makeKeyWindow]; } return self; } /*-------------------------------------------------------------------- |-switchViewMode:sender| * Toggle between view and edit mode Returns self. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -switchViewMode:sender { return [self setViewMode:(! viewMode)]; } /*==================================================================== Action Methods ====================================================================*/ /* Action methods for Card View/Edit */ /*-------------------------------------------------------------------- |-reveal:sender| * If I ask, display RES. If Button asks, toggle. Returns self. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -reveal:sender { id scroll = [[textView[RES] superview] superview]; if ((sender == self) || ([scroll backgroundGray] == NX_BLACK)) [[scroll setBackgroundGray:NX_WHITE] update]; else [self cover:self]; return self; } /*-------------------------------------------------------------------- |-cover:sender| * Blacken RES. Returns self. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -cover:sender { id scroll = [[textView[RES] superview] superview]; [[scroll setBackgroundGray:NX_BLACK] update]; return self; } /*-------------------------------------------------------------------- |-wasEasy:sender| * Place in Back. Returns self. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -wasEasy:sender { [self nextCard]; return self; } /*-------------------------------------------------------------------- |-wasFair:sender| Make sure you will see it again. Returns self. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -wasFair:sender { int location = [rand randMin:0 max:current]; id card = [contents removeObjectAt:current]; [contents insertObject:card at:location]; ++current; [self nextCard]; return self; } /*-------------------------------------------------------------------- |-wasHard:sender| Make sure you will see it again soon. Returns self. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -wasHard:sender { int location = [rand randMin:(current/2) max:current]; id card = [contents removeObjectAt:current]; [contents insertObject:card at:location]; ++current; [self nextCard]; return self; } /*==================================================================== Edit Mode ====================================================================*/ /*-------------------------------------------------------------------- |-next:sender| * Show the next card. If current one has been changed, ask. Returns self. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -next:sender { [self sync]; [self nextCard]; return self; } /*-------------------------------------------------------------------- |-revertCard:sender| Undo whatever changes have been made to this Card Returns self. Ernest Prabhakar/1991-Oct-07 --------------------------------------------------------------------*/ -revertCard:sender { readFromCard([contents objectAt:current],textView); return self; } /*-------------------------------------------------------------------- |-modify:sender| * Change the current Card. Returns self. Ernest Prabhakar/1991-Oct-12 --------------------------------------------------------------------*/ -modify:sender { [self saveCard]; return [self nextCard]; } /*-------------------------------------------------------------------- |-delete:sender| * Delete the current Card. Returns self. Ernest Prabhakar/1991-Oct-12 --------------------------------------------------------------------*/ -delete:sender { if (NXRunAlertPanel("Delete", "Are you sure you want to delete this card?", "YES", "NO", "Cancel") != NX_ALERTDEFAULT) return self; [window setDocEdited:YES]; [[contents removeObjectAt:current] free]; return [self nextCard]; } /*==================================================================== Action Methods for manipulating the Deck ====================================================================*/ /*-------------------------------------------------------------------- |-previous:sender| * Move back one. Returns self. Ernest Prabhakar/1991-Oct-12 --------------------------------------------------------------------*/ -previous:sender { [self sync]; current += 2; if (current > [contents count]) current = [contents count]; return [self nextCard]; } /*-------------------------------------------------------------------- |-find:sender| * Find a string. Use a panel to set parameters Returns self. Ernest Prabhakar/1991-Oct-14 --------------------------------------------------------------------*/ -find:sender { id card = [super find:sender]; if (card) { [self sync]; current = [contents indexOf:card] + 1; [self nextCard]; } return self; } /*-------------------------------------------------------------------- |-doAct:(SEL)action for:(STR)caller| * Pass action methods on to Deck Returns self. Ernest Prabhakar/1991-Oct-12 --------------------------------------------------------------------*/ -doAct:(SEL)action for:(STR)caller { [self sync]; [contents perform:action]; [window setDocEdited:YES]; current = [contents count]; return [self nextCard]; } /*-------------------------------------------------------------------- |-shuffle:sender| * Shuffle the deck. Returns self. Ernest Prabhakar/1991-Oct-12 --------------------------------------------------------------------*/ -shuffle:sender { return [self doAct:@selector(shuffle) for:"shuffle"]; } /*-------------------------------------------------------------------- |-sort:sender| * Organize in some coherent fashion. Use a default sort on key. Returns self. Ernest Prabhakar/1991-Oct-12 --------------------------------------------------------------------*/ -sort:sender { [self sync]; [contents sort]; return [self doAct:@selector(reverse) for:"sort"]; } -swapFields:sender /* * Exchange Key and Response. */ { #ifdef SWAPPING return [self doAct:@selector(rotate) for:"swap fields"]; #else return nil; #endif } - reset:sender { [self sync]; current = [contents count]; [markCount setIntValue:current]; return [self nextCard]; } /*==================================================================== Action Methods for File services ====================================================================*/ /*-------------------------------------------------------------------- |-print:sender| * Create a view displaying the entire deck, staggered. Then print it. Returns self. *** NOT FULLY FUNCTIONAL *** Ernest Prabhakar/1991-Oct-15 --------------------------------------------------------------------*/ -print:sender { NXRect myRect; Window *holder; id deckView; id aText, bText; NXCoord Height, height; int count; [self sync]; count = [contents count]; NXSetRect(&myRect, 0.0, 0.0, 2*P_WIDE, (count+1)*P_HIGH); holder = [ZAlloc(Window) initContent:&myRect style:NX_PLAINSTYLE backing: NX_NONRETAINED buttonMask:0 defer:NO]; deckView = [ZAlloc(NXSplitView) initFrame:&myRect]; [holder setContentView:deckView]; Height = count * [deckView dividerHeight]; /* Set up Prototype Text and Box */ bText = newText(1); [bText setText:[self filename]]; while (count--) { id card = [contents objectAt:count]; aText = newText(0); setText(aText, [card stringStreamAt:0], [card intValueAt:0]); [deckView addSubview:wrapViews(aText, bText, &height)]; Height += height; bText = newText(1); setText(bText, [card stringStreamAt:1], [card intValueAt:1]); } aText = newText(0); [aText setText:[self filename]]; [deckView addSubview:wrapViews(aText, bText, &height)]; Height += height; NXSetRect(&myRect, 0.0, 0.0, 2*P_WIDE, Height); [[deckView setFrame:&myRect] printPSCode:sender]; [holder close]; return self; } /*==================================================================== Text delegate methods. ====================================================================*/ /*-------------------------------------------------------------------- |-(BOOL)textWillChange:sender| Doesn't allow editing in view mode. Returns self. Ernest Prabhakar/1991-Oct-14 --------------------------------------------------------------------*/ -(BOOL)textWillChange:sender { if (viewMode) { Notify("Edit", "Can only edit cards in Edit Mode."); return YES; } else { cardChanged = YES; return NO; } } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.