void ColorBitmapText::DrawPrimitives( ) { Actor::SetGlobalRenderStates(); // set Actor-specified render states DISPLAY->SetTextureMode( TextureUnit_1, TextureMode_Modulate ); /* Draw if we're not fully transparent or the zbuffer is enabled */ if( m_pTempState->diffuse[0].a != 0 ) { // // render the shadow // if( m_fShadowLengthX != 0 || m_fShadowLengthY != 0 ) { DISPLAY->PushMatrix(); DISPLAY->TranslateWorld( m_fShadowLengthX, m_fShadowLengthY, 0 ); // shift by 5 units RageColor c = m_ShadowColor; c.a *= m_pTempState->diffuse[0].a; for( unsigned i=0; i<m_aVertices.size(); i++ ) m_aVertices[i].c = c; DrawChars( true ); DISPLAY->PopMatrix(); } // // render the diffuse pass // int loc = 0, cur = 0; RageColor c = m_pTempState->diffuse[0]; for( unsigned i=0; i<m_aVertices.size(); i+=4 ) { loc++; if( cur < (int)m_vColors.size() ) { if ( loc > m_vColors[cur].l ) { c = m_vColors[cur].c; cur++; } } for( unsigned j=0; j<4; j++ ) m_aVertices[i+j].c = c; } DrawChars( false ); } /* render the glow pass */ if( m_pTempState->glow.a > 0.0001f ) { DISPLAY->SetTextureMode( TextureUnit_1, TextureMode_Glow ); for( unsigned i=0; i<m_aVertices.size(); i++ ) m_aVertices[i].c = m_pTempState->glow; DrawChars( false ); } }
void ColorBitmapText::DrawPrimitives( ) { Actor::SetGlobalRenderStates(); // set Actor-specified render states DISPLAY->SetTextureModeModulate(); /* Draw if we're not fully transparent or the zbuffer is enabled */ if( m_pTempState->diffuse[0].a != 0 ) { ////////////////////// // render the shadow ////////////////////// if( m_fShadowLength != 0 ) { DISPLAY->PushMatrix(); DISPLAY->TranslateWorld( m_fShadowLength, m_fShadowLength, 0 ); // shift by 5 units RageColor dim(0,0,0,0.5f*m_pTempState->diffuse[0].a); // semi-transparent black for( unsigned i=0; i<m_aVertices.size(); i++ ) m_aVertices[i].c = dim; DrawChars(); DISPLAY->PopMatrix(); } ////////////////////// // render the diffuse pass ////////////////////// int loc = 0, cur = 0; RageColor c = m_pTempState->diffuse[0]; for( unsigned i=0; i<m_aVertices.size(); i+=4 ) { loc++; if ( cur < (int)m_vColors.size() ) if ( loc > m_vColors[cur].l ) { c = m_vColors[cur].c; cur++; } for ( unsigned j=0; j<4; j++ ) m_aVertices[i+j].c = c; } DrawChars(); } /* render the glow pass */ if( m_pTempState->glow.a > 0.0001f ) { DISPLAY->SetTextureModeGlow(); for( unsigned i=0; i<m_aVertices.size(); i++ ) m_aVertices[i].c = m_pTempState->glow; DrawChars(); } Actor::DrawPrimitives(); }
//----------------------------------------------------------------------------- // Draw a vertical wire one leaf element unit high up from (cx, cy), where cx // and cy are in charcter units. //----------------------------------------------------------------------------- static void VerticalWire(int cx, int cy) { int j; for(j = 1; j < POS_HEIGHT; j++) { DrawChars(cx, cy + (POS_HEIGHT/2 - j), "|"); } DrawChars(cx, cy + (POS_HEIGHT/2), "+"); DrawChars(cx, cy + (POS_HEIGHT/2 - POS_HEIGHT), "+"); }
//----------------------------------------------------------------------------- // Draw the rung that signals the end of the program. Kind of useless but // do it anyways, for convention. //----------------------------------------------------------------------------- void DrawEndRung(int cx, int cy) { int i; char *str = "[END]"; int lead = (POS_WIDTH - strlen(str))/2; ThisHighlighted = TRUE; for(i = 0; i < lead; i++) { DrawChars(cx + i, cy + (POS_HEIGHT/2), "-"); } DrawChars(cx + i, cy + (POS_HEIGHT/2), str); i += strlen(str); for(; i < ColsAvailable*POS_WIDTH; i++) { DrawChars(cx + i, cy + (POS_HEIGHT/2), "-"); } }
// ************************************************************************* // Draw an item on the screen // ************************************************************************* static void DrawItem( char* Name, int y, long Price ) { int j; FntSetFont( stdFont ); DrawChars( Name, 30, y ); EraseRectangle( 110, y, 56, 9 ); StrIToA( SBuf, Price ); StrCat( SBuf, " cr." ); j = MAXDIGITS - StrLen( SBuf ); if (Price > 0) DrawChars( SBuf, 124+j*5, y ); else DrawChars( "not sold", 122, y ); }
//----------------------------------------------------------------------------- // Like CenterWithWires, but for an arbitrary width position (e.g. for ADD // and SUB, which are double-width). //----------------------------------------------------------------------------- static void CenterWithWiresWidth(int cx, int cy, char *str, BOOL before, BOOL after, int totalWidth) { int extra = totalWidth - FormattedStrlen(str); PoweredText(after); DrawChars(cx + (extra/2), cy + (POS_HEIGHT/2), str); PoweredText(before); int i; for(i = 0; i < (extra/2); i++) { DrawChars(cx + i, cy + (POS_HEIGHT/2), "-"); } PoweredText(after); for(i = FormattedStrlen(str)+(extra/2); i < totalWidth; i++) { DrawChars(cx + i, cy + (POS_HEIGHT/2), "-"); } }
//----------------------------------------------------------------------------- // Draw a string, centred in the space of a single position, with spaces on // the left and right. Draws on the upper line of the position. //----------------------------------------------------------------------------- static void CenterWithSpaces(int cx, int cy, char *str, BOOL powered, BOOL isName) { int extra = POS_WIDTH - FormattedStrlen(str); PoweredText(powered); if(isName) NameText(); DrawChars(cx + (extra/2), cy + (POS_HEIGHT/2) - 1, str); if(isName) BodyText(); }
// draw text at x, y using colorTop blended down to colorBottom, with size multiplied by scale void BitmapText::DrawPrimitives() { Actor::SetGlobalRenderStates(); // set Actor-specified render states DISPLAY->SetTextureModeModulate(); /* Draw if we're not fully transparent or the zbuffer is enabled */ if( m_pTempState->diffuse[0].a != 0 ) { ////////////////////// // render the shadow ////////////////////// if( m_fShadowLength != 0 ) { DISPLAY->PushMatrix(); DISPLAY->TranslateWorld( m_fShadowLength, m_fShadowLength, 0 ); // shift by 5 units RageColor dim(0,0,0,0.5f*m_pTempState->diffuse[0].a); // semi-transparent black for( unsigned i=0; i<m_aVertices.size(); i++ ) m_aVertices[i].c = dim; DrawChars(); DISPLAY->PopMatrix(); } ////////////////////// // render the diffuse pass ////////////////////// if( m_bRainbow ) { int color_index = int(RageTimer::GetTimeSinceStartFast() / 0.200) % NUM_RAINBOW_COLORS; for( unsigned i=0; i<m_aVertices.size(); i+=4 ) { const RageColor color = RAINBOW_COLORS[color_index]; for( unsigned j=i; j<i+4; j++ ) m_aVertices[j].c = color; color_index = (color_index+1)%NUM_RAINBOW_COLORS; } } else { for( unsigned i=0; i<m_aVertices.size(); i+=4 ) { m_aVertices[i+0].c = m_pTempState->diffuse[0]; // top left m_aVertices[i+1].c = m_pTempState->diffuse[2]; // bottom left m_aVertices[i+2].c = m_pTempState->diffuse[3]; // bottom right m_aVertices[i+3].c = m_pTempState->diffuse[1]; // top right } } DrawChars(); } /* render the glow pass */ if( m_pTempState->glow.a > 0.0001f ) { DISPLAY->SetTextureModeGlow(); for( unsigned i=0; i<m_aVertices.size(); i++ ) m_aVertices[i].c = m_pTempState->glow; DrawChars(); } }
// draw text at x, y using colorTop blended down to colorBottom, with size multiplied by scale void BitmapText::DrawPrimitives() { Actor::SetGlobalRenderStates(); // set Actor-specified render states DISPLAY->SetTextureMode( TextureUnit_1, TextureMode_Modulate ); // Draw if we're not fully transparent or the zbuffer is enabled if( m_pTempState->diffuse[0].a != 0 ) { // render the shadow if( m_fShadowLengthX != 0 || m_fShadowLengthY != 0 ) { DISPLAY->PushMatrix(); DISPLAY->TranslateWorld( m_fShadowLengthX, m_fShadowLengthY, 0 ); RageColor c = m_ShadowColor; c.a *= m_pTempState->diffuse[0].a; for( unsigned i=0; i<m_aVertices.size(); i++ ) m_aVertices[i].c = c; DrawChars( false ); DISPLAY->PopMatrix(); } // render the stroke if( m_StrokeColor.a > 0 ) { RageColor c = m_StrokeColor; c.a *= m_pTempState->diffuse[0].a; for( unsigned i=0; i<m_aVertices.size(); i++ ) m_aVertices[i].c = c; DrawChars( true ); } // render the diffuse pass if( m_bRainbowScroll ) { int color_index = int(RageTimer::GetTimeSinceStartFast() / 0.200) % RAINBOW_COLORS.size(); for( unsigned i=0; i<m_aVertices.size(); i+=4 ) { const RageColor color = RAINBOW_COLORS[color_index]; for( unsigned j=i; j<i+4; j++ ) m_aVertices[j].c = color; color_index = (color_index+1) % RAINBOW_COLORS.size(); } } else { size_t i = 0; map<size_t,Attribute>::const_iterator iter = m_mAttributes.begin(); while( i < m_aVertices.size() ) { // Set the colors up to the next attribute. size_t iEnd = iter == m_mAttributes.end()? m_aVertices.size():iter->first*4; iEnd = min( iEnd, m_aVertices.size() ); for( ; i < iEnd; i += 4 ) { m_aVertices[i+0].c = m_pTempState->diffuse[0]; // top left m_aVertices[i+1].c = m_pTempState->diffuse[2]; // bottom left m_aVertices[i+2].c = m_pTempState->diffuse[3]; // bottom right m_aVertices[i+3].c = m_pTempState->diffuse[1]; // top right } if( iter == m_mAttributes.end() ) break; // Set the colors according to this attribute. const Attribute &attr = iter->second; ++iter; if( attr.length < 0 ) iEnd = iter == m_mAttributes.end()? m_aVertices.size():iter->first*4; else iEnd = i + attr.length*4; iEnd = min( iEnd, m_aVertices.size() ); for( ; i < iEnd; i += 4 ) { m_aVertices[i+0].c = attr.diffuse[0]; // top left m_aVertices[i+1].c = attr.diffuse[2]; // bottom left m_aVertices[i+2].c = attr.diffuse[3]; // bottom right m_aVertices[i+3].c = attr.diffuse[1]; // top right } } } // apply jitter to verts vector<RageVector3> vGlyphJitter; if( m_bJitter ) { int iSeed = lrintf( RageTimer::GetTimeSinceStartFast()*8 ); RandomGen rnd( iSeed ); for( unsigned i=0; i<m_aVertices.size(); i+=4 ) { RageVector3 jitter( rnd()%2, rnd()%3, 0 ); vGlyphJitter.push_back( jitter ); m_aVertices[i+0].p += jitter; // top left m_aVertices[i+1].p += jitter; // bottom left m_aVertices[i+2].p += jitter; // bottom right m_aVertices[i+3].p += jitter; // top right } } DrawChars( false ); // undo jitter to verts if( m_bJitter ) { ASSERT( vGlyphJitter.size() == m_aVertices.size()/4 ); for( unsigned i=0; i<m_aVertices.size(); i+=4 ) { const RageVector3 &jitter = vGlyphJitter[i/4];; m_aVertices[i+0].p -= jitter; // top left m_aVertices[i+1].p -= jitter; // bottom left m_aVertices[i+2].p -= jitter; // bottom right m_aVertices[i+3].p -= jitter; // top right } } } // render the glow pass if( m_pTempState->glow.a > 0.0001f || m_bHasGlowAttribute ) { DISPLAY->SetTextureMode( TextureUnit_1, TextureMode_Glow ); size_t i = 0; map<size_t,Attribute>::const_iterator iter = m_mAttributes.begin(); while( i < m_aVertices.size() ) { // Set the glow up to the next attribute. size_t iEnd = iter == m_mAttributes.end()? m_aVertices.size():iter->first*4; iEnd = min( iEnd, m_aVertices.size() ); for( ; i < iEnd; ++i ) m_aVertices[i].c = m_pTempState->glow; if( iter == m_mAttributes.end() ) break; // Set the glow according to this attribute. const Attribute &attr = iter->second; ++iter; if( attr.length < 0 ) iEnd = iter == m_mAttributes.end()? m_aVertices.size():iter->first*4; else iEnd = i + attr.length*4; iEnd = min( iEnd, m_aVertices.size() ); for( ; i < iEnd; ++i ) m_aVertices[i].c = attr.glow; } /* Draw glow using the base texture and the glow texture. Otherwise, * glow looks too tame on BitmapText that has a stroke. - Chris Danford */ /* This doesn't work well if the font is using an invisible stroke, as * the invisible stroke will glow as well. Time for TextGlowMode. * Only draw the strokes if the glow mode is not inner only. -aj */ DrawChars(m_TextGlowMode != TextGlowMode_Inner); } }
static void DrawCurrentShipForm() { FormPtr frmP = FrmGetActiveForm(); int i, j, k, Line, FirstEmptySlot; RectangularShortcuts( frmP, CurrentShipBButton ); FrmDrawForm( frmP ); FntSetFont( boldFont ); DrawChars( "Type:", 0, 18 ); DrawChars( "Equipment:", 0, 32 ); FntSetFont( stdFont ); if (ScarabStatus == 3) { StrCopy( SBuf, Shiptype[Ship.Type].Name); StrCat ( SBuf, "/hardened hull"); DrawChars( SBuf, 60, 18 ); } else DrawChars( Shiptype[Ship.Type].Name, 60, 18 ); Line = 32; for (i=0; i<MAXWEAPONTYPE+EXTRAWEAPONS; ++i) { j = 0; for (k=0; k<MAXWEAPON; ++k) { if (Ship.Weapon[k] == i) ++j; } if (j > 0) { SBuf[0] = '\0'; SBufMultiples( j, Weapontype[i].Name ); StrToLower( SBuf2, SBuf ); DrawChars( SBuf2, 60, Line ); Line += 14; } } for (i=0; i<MAXSHIELDTYPE+EXTRASHIELDS; ++i) { j = 0; for (k=0; k<MAXSHIELD; ++k) { if (Ship.Shield[k] == i) ++j; } if (j > 0) { SBuf[0] = '\0'; SBufMultiples( j, Shieldtype[i].Name ); StrToLower( SBuf2, SBuf ); DrawChars( SBuf2, 60, Line ); Line += 14; } } for (i=0; i<MAXGADGETTYPE+EXTRAGADGETS; ++i) { j = 0; for (k=0; k<MAXGADGET; ++k) { if (Ship.Gadget[k] == i) ++j; } if (j > 0) { if (i == EXTRABAYS) { j = j*5; StrIToA( SBuf, j ); StrCat( SBuf, " extra cargo bays" ); } else { StrCopy(SBuf, Gadgettype[i].Name ); } StrToLower( SBuf2, SBuf ); DrawChars( SBuf2, 60, Line ); Line += 14; } } if (EscapePod) { DrawChars( "an escape pod", 60, Line ); Line += 14; } if (AnyEmptySlots(&Ship)) { FntSetFont( boldFont ); DrawChars( "Unfilled: ", 0, Line ); FntSetFont( stdFont ); FirstEmptySlot = GetFirstEmptySlot( Shiptype[Ship.Type].WeaponSlots, Ship.Weapon ); if (FirstEmptySlot >= 0) { SBuf[0] = '\0'; SBufMultiples( Shiptype[Ship.Type].WeaponSlots - FirstEmptySlot, "weapon slot" ); DrawChars( SBuf, 60, Line ); Line += 14; } FirstEmptySlot = GetFirstEmptySlot( Shiptype[Ship.Type].ShieldSlots, Ship.Shield ); if (FirstEmptySlot >= 0) { SBuf[0] = '\0'; SBufMultiples( Shiptype[Ship.Type].ShieldSlots - FirstEmptySlot, "shield slot" ); DrawChars( SBuf, 60, Line ); Line += 14; } FirstEmptySlot = GetFirstEmptySlot( Shiptype[Ship.Type].GadgetSlots, Ship.Gadget ); if (FirstEmptySlot >= 0) { SBuf[0] = '\0'; SBufMultiples( Shiptype[Ship.Type].GadgetSlots - FirstEmptySlot, "gadget slot" ); DrawChars( SBuf, 60, Line ); Line += 14; } } }
//----------------------------------------------------------------------------- // Draw a particular subcircuit with its top left corner at *cx and *cy (in // characters). If it is a leaf element then just print it and return; else // loop over the elements of the subcircuit and call ourselves recursively. // At the end updates *cx and *cy. // // In simulation mode, returns TRUE the circuit is energized after the given // element, else FALSE. This is needed to colour all the wires correctly, // since the colouring indicates whether a wire is energized. //----------------------------------------------------------------------------- BOOL DrawElement(int which, void *elem, int *cx, int *cy, BOOL poweredBefore) { BOOL poweredAfter; int cx0 = *cx, cy0 = *cy; ElemLeaf *leaf = (ElemLeaf *)elem; SetBkColor(Hdc, InSimulationMode ? HighlightColours.simBg : HighlightColours.bg); NormText(); if(elem == Selected && !InSimulationMode) { EmphText(); ThisHighlighted = TRUE; } else { ThisHighlighted = FALSE; } switch(which) { case ELEM_SERIES_SUBCKT: { int i; ElemSubcktSeries *s = (ElemSubcktSeries *)elem; poweredAfter = poweredBefore; for(i = 0; i < s->count; i++) { poweredAfter = DrawElement(s->contents[i].which, s->contents[i].d.any, cx, cy, poweredAfter); } break; } case ELEM_PARALLEL_SUBCKT: { int i; ElemSubcktParallel *p = (ElemSubcktParallel *)elem; int widthMax = CountWidthOfElement(which, elem, (*cx)/POS_WIDTH); int heightMax = CountHeightOfElement(which, elem); poweredAfter = FALSE; int lowestPowered = -1; int downBy = 0; for(i = 0; i < p->count; i++) { BOOL poweredThis; poweredThis = DrawElement(p->contents[i].which, p->contents[i].d.any, cx, cy, poweredBefore); if(InSimulationMode) { if(poweredThis) poweredAfter = TRUE; PoweredText(poweredThis); } while((*cx - cx0) < widthMax*POS_WIDTH) { int gx = *cx/POS_WIDTH; int gy = *cy/POS_HEIGHT; if(CheckBoundsUndoIfFails(gx, gy)) return FALSE; DM_BOUNDS(gx, gy); DisplayMatrix[gx][gy] = PADDING_IN_DISPLAY_MATRIX; DisplayMatrixWhich[gx][gy] = ELEM_PADDING; char buf[256]; int j; for(j = 0; j < POS_WIDTH; j++) { buf[j] = '-'; } buf[j] = '\0'; DrawChars(*cx, *cy + (POS_HEIGHT/2), buf); *cx += POS_WIDTH; } *cx = cx0; int justDrewHeight = CountHeightOfElement(p->contents[i].which, p->contents[i].d.any); *cy += POS_HEIGHT*justDrewHeight; downBy += justDrewHeight; if(poweredThis) { lowestPowered = downBy - 1; } } *cx = cx0 + POS_WIDTH*widthMax; *cy = cy0; int j; BOOL needWire; if(*cx/POS_WIDTH != ColsAvailable) { needWire = FALSE; for(j = heightMax - 1; j >= 1; j--) { if(j <= lowestPowered) PoweredText(poweredAfter); if(DisplayMatrix[*cx/POS_WIDTH - 1][*cy/POS_HEIGHT + j]) { needWire = TRUE; } if(needWire) VerticalWire(*cx - 1, *cy + j*POS_HEIGHT); } // stupid special case if(lowestPowered == 0 && InSimulationMode) { EmphText(); DrawChars(*cx - 1, *cy + (POS_HEIGHT/2), "+"); } } PoweredText(poweredBefore); needWire = FALSE; for(j = heightMax - 1; j >= 1; j--) { if(DisplayMatrix[cx0/POS_WIDTH][*cy/POS_HEIGHT + j]) { needWire = TRUE; } if(needWire) VerticalWire(cx0 - 1, *cy + j*POS_HEIGHT); } break; } default: poweredAfter = DrawLeaf(which, leaf, cx, cy, poweredBefore); break; } NormText(); return poweredAfter; }
//----------------------------------------------------------------------------- // Draw a leaf element. Special things about a leaf: no need to recurse // further, and we must put it into the display matrix. //----------------------------------------------------------------------------- static BOOL DrawLeaf(int which, ElemLeaf *leaf, int *cx, int *cy, BOOL poweredBefore) { int cx0 = *cx, cy0 = *cy; BOOL poweredAfter = leaf->poweredAfter; switch(which) { case ELEM_COMMENT: { char tbuf[MAX_COMMENT_LEN]; char tlbuf[MAX_COMMENT_LEN+8]; strcpy(tbuf, leaf->d.comment.str); char *b = strchr(tbuf, '\n'); if(b) { if(b[-1] == '\r') b[-1] = '\0'; *b = '\0'; sprintf(tlbuf, "\x03 ; %s\x02", tbuf); DrawChars(*cx, *cy + (POS_HEIGHT/2) - 1, tlbuf); sprintf(tlbuf, "\x03 ; %s\x02", b+1); DrawChars(*cx, *cy + (POS_HEIGHT/2), tlbuf); } else { sprintf(tlbuf, "\x03 ; %s\x02", tbuf); DrawChars(*cx, *cy + (POS_HEIGHT/2) - 1, tlbuf); } *cx += ColsAvailable*POS_WIDTH; break; } case ELEM_PLACEHOLDER: { NormText(); CenterWithWiresWidth(*cx, *cy, "--", FALSE, FALSE, 2); *cx += POS_WIDTH; break; } case ELEM_CONTACTS: { char buf[4]; ElemContacts *c = &leaf->d.contacts; buf[0] = ']'; buf[1] = c->negated ? '/' : ' '; buf[2] = '['; buf[3] = '\0'; CenterWithSpaces(*cx, *cy, c->name, poweredAfter, TRUE); CenterWithWires(*cx, *cy, buf, poweredBefore, poweredAfter); *cx += POS_WIDTH; break; } { char *s; case ELEM_EQU: s = "=="; goto cmp; case ELEM_NEQ: s = "/="; goto cmp; case ELEM_GRT: s = ">"; goto cmp; case ELEM_GEQ: s = ">="; goto cmp; case ELEM_LES: s = "<"; goto cmp; case ELEM_LEQ: s = "<="; goto cmp; cmp: char s1[POS_WIDTH+10], s2[POS_WIDTH+10]; int l1, l2, lmax; l1 = 2 + 1 + strlen(s) + strlen(leaf->d.cmp.op1); l2 = 2 + 1 + strlen(leaf->d.cmp.op2); lmax = max(l1, l2); memset(s1, ' ', sizeof(s1)); s1[0] = '['; int lcmp = lmax < POS_WIDTH ? lmax : POS_WIDTH; s1[lcmp - 1] = ']'; s1[lcmp] = '\0'; strcpy(s2, s1); if(l1 >= POS_WIDTH) { memcpy(s1 + 1, leaf->d.cmp.op1, 3); memset(s1 + 4, '.', 3); memcpy(s1 + 7, leaf->d.cmp.op1 + strlen(leaf->d.cmp.op1) - 3, 3); memcpy(s1 + 9 + 2, s, strlen(s)); } else { memcpy(s1 + 1, leaf->d.cmp.op1, strlen(leaf->d.cmp.op1)); memcpy(s1 + strlen(leaf->d.cmp.op1) + 2, s, strlen(s)); } if(l2 >= POS_WIDTH) { memcpy(s2 + 1, leaf->d.cmp.op2, 3); memset(s2 + 4, '.', 3); memcpy(s2 + 7, leaf->d.cmp.op2 + strlen(leaf->d.cmp.op2) - 3, 3); } else { memcpy(s2 + 2, leaf->d.cmp.op2, strlen(leaf->d.cmp.op2)); } CenterWithSpaces(*cx, *cy, s1, poweredAfter, FALSE); CenterWithWires(*cx, *cy, s2, poweredBefore, poweredAfter); *cx += POS_WIDTH; break; } case ELEM_OPEN: CenterWithWires(*cx, *cy, "+ +", poweredBefore, poweredAfter); *cx += POS_WIDTH; break; case ELEM_SHORT: CenterWithWires(*cx, *cy, "+------+", poweredBefore, poweredAfter); *cx += POS_WIDTH; break; case ELEM_ONE_SHOT_RISING: case ELEM_ONE_SHOT_FALLING: { char *s1, *s2; if(which == ELEM_ONE_SHOT_RISING) { s1 = " _ "; s2 = "[\x01OSR\x02_/ ]"; } else if(which == ELEM_ONE_SHOT_FALLING) { s1 = " _ "; s2 = "[\x01OSF\x02 \\_]"; } else oops(); CenterWithSpaces(*cx, *cy, s1, poweredAfter, FALSE); CenterWithWires(*cx, *cy, s2, poweredBefore, poweredAfter); *cx += POS_WIDTH; break; } case ELEM_CTU: case ELEM_CTD: { char *s; if(which == ELEM_CTU) s = "\x01""CTU\x02"; else if(which == ELEM_CTD) s = "\x01""CTD\x02"; else oops(); char buf[256]; ElemCounter *c = &leaf->d.counter; sprintf(buf, "[%s >=%d]", s, c->max); CenterWithSpaces(*cx, *cy, c->name, poweredAfter, TRUE); CenterWithWires(*cx, *cy, buf, poweredBefore, poweredAfter); *cx += POS_WIDTH; break; } case ELEM_RTO: case ELEM_TON: case ELEM_TOF: { char *s; if(which == ELEM_TON) s = "\x01TON\x02"; else if(which == ELEM_TOF) s = "\x01TOF\x02"; else if(which == ELEM_RTO) s = "\x01RTO\x02"; else oops(); char buf[256]; ElemTimer *t = &leaf->d.timer; if(t->delay >= 1000*1000) { sprintf(buf, "[%s %.3f s]", s, t->delay/1000000.0); } else if(t->delay >= 100*1000) { sprintf(buf, "[%s %.1f ms]", s, t->delay/1000.0); } else { sprintf(buf, "[%s %.2f ms]", s, t->delay/1000.0); } CenterWithSpaces(*cx, *cy, t->name, poweredAfter, TRUE); CenterWithWires(*cx, *cy, buf, poweredBefore, poweredAfter); *cx += POS_WIDTH; break; } case ELEM_FORMATTED_STRING: { // Careful, string could be longer than fits in our space. char str[POS_WIDTH*2]; memset(str, 0, sizeof(str)); char *srcStr = leaf->d.fmtdStr.string; memcpy(str, srcStr, min(strlen(srcStr), POS_WIDTH*2 - 7)); char bot[100]; sprintf(bot, "{\"%s\"}", str); int extra = 2*POS_WIDTH - strlen(leaf->d.fmtdStr.var); PoweredText(poweredAfter); NameText(); DrawChars(*cx + (extra/2), *cy + (POS_HEIGHT/2) - 1, leaf->d.fmtdStr.var); BodyText(); CenterWithWiresWidth(*cx, *cy, bot, poweredBefore, poweredAfter, 2*POS_WIDTH); *cx += 2*POS_WIDTH; break; } case ELEM_UART_RECV: case ELEM_UART_SEND: CenterWithWires(*cx, *cy, (char *)((which == ELEM_UART_RECV) ? "{UART RECV}" : "{UART SEND}"), poweredBefore, poweredAfter); CenterWithSpaces(*cx, *cy, leaf->d.uart.name, poweredAfter, TRUE); *cx += POS_WIDTH; break; default: poweredAfter = DrawEndOfLine(which, leaf, cx, cy, poweredBefore); break; } // And now we can enter the element into the display matrix so that the // UI routines know what element is at position (gx, gy) when the user // clicks there, and so that we know where to put the cursor if this // element is selected. // Don't use original cx0, as an end of line element might be further // along than that. cx0 = *cx - POS_WIDTH; int gx = cx0/POS_WIDTH; int gy = cy0/POS_HEIGHT; if(CheckBoundsUndoIfFails(gx, gy)) return FALSE; DM_BOUNDS(gx, gy); DisplayMatrix[gx][gy] = leaf; DisplayMatrixWhich[gx][gy] = which; int xadj = 0; switch(which) { case ELEM_ADD: case ELEM_SUB: case ELEM_MUL: case ELEM_DIV: case ELEM_FORMATTED_STRING: DM_BOUNDS(gx-1, gy); DisplayMatrix[gx-1][gy] = leaf; DisplayMatrixWhich[gx-1][gy] = which; xadj = POS_WIDTH*FONT_WIDTH; break; } if(which == ELEM_COMMENT) { int i; for(i = 0; i < ColsAvailable; i++) { DisplayMatrix[i][gy] = leaf; DisplayMatrixWhich[i][gy] = ELEM_COMMENT; } xadj = (ColsAvailable-1)*POS_WIDTH*FONT_WIDTH; } int x0 = X_PADDING + cx0*FONT_WIDTH; int y0 = Y_PADDING + cy0*FONT_HEIGHT; if(leaf->selectedState != SELECTED_NONE && leaf == Selected) { SelectionActive = TRUE; } switch(leaf->selectedState) { case SELECTED_LEFT: Cursor.left = x0 + FONT_WIDTH - 4 - xadj; Cursor.top = y0 - FONT_HEIGHT/2; Cursor.width = 2; Cursor.height = POS_HEIGHT*FONT_HEIGHT; break; case SELECTED_RIGHT: Cursor.left = x0 + (POS_WIDTH-1)*FONT_WIDTH - 5; Cursor.top = y0 - FONT_HEIGHT/2; Cursor.width = 2; Cursor.height = POS_HEIGHT*FONT_HEIGHT; break; case SELECTED_ABOVE: Cursor.left = x0 + FONT_WIDTH/2 - xadj; Cursor.top = y0 - 2; Cursor.width = (POS_WIDTH-2)*FONT_WIDTH + xadj; Cursor.height = 2; break; case SELECTED_BELOW: Cursor.left = x0 + FONT_WIDTH/2 - xadj; Cursor.top = y0 + (POS_HEIGHT-1)*FONT_HEIGHT + FONT_HEIGHT/2 - 2; Cursor.width = (POS_WIDTH-2)*(FONT_WIDTH) + xadj; Cursor.height = 2; break; default: break; } return poweredAfter; }
//----------------------------------------------------------------------------- // Draw an end of line element (coil, RES, MOV, etc.). Special things about // an end of line element: we must right-justify it. //----------------------------------------------------------------------------- static BOOL DrawEndOfLine(int which, ElemLeaf *leaf, int *cx, int *cy, BOOL poweredBefore) { int cx0 = *cx, cy0 = *cy; BOOL poweredAfter = leaf->poweredAfter; int thisWidth; switch(which) { case ELEM_ADD: case ELEM_SUB: case ELEM_MUL: case ELEM_DIV: thisWidth = 2; break; default: thisWidth = 1; break; } NormText(); PoweredText(poweredBefore); while(*cx < (ColsAvailable-thisWidth)*POS_WIDTH) { int gx = *cx/POS_WIDTH; int gy = *cy/POS_HEIGHT; if(CheckBoundsUndoIfFails(gx, gy)) return FALSE; if(gx >= DISPLAY_MATRIX_X_SIZE) oops(); DM_BOUNDS(gx, gy); DisplayMatrix[gx][gy] = PADDING_IN_DISPLAY_MATRIX; DisplayMatrixWhich[gx][gy] = ELEM_PADDING; int i; for(i = 0; i < POS_WIDTH; i++) { DrawChars(*cx + i, *cy + (POS_HEIGHT/2), "-"); } *cx += POS_WIDTH; cx0 += POS_WIDTH; } if(leaf == Selected && !InSimulationMode) { EmphText(); ThisHighlighted = TRUE; } else { ThisHighlighted = FALSE; } switch(which) { case ELEM_CTC: { char buf[256]; ElemCounter *c = &leaf->d.counter; sprintf(buf, "{\x01""CTC\x02 0:%d}", c->max); CenterWithSpaces(*cx, *cy, c->name, poweredAfter, TRUE); CenterWithWires(*cx, *cy, buf, poweredBefore, poweredAfter); break; } case ELEM_RES: { ElemReset *r = &leaf->d.reset; CenterWithSpaces(*cx, *cy, r->name, poweredAfter, TRUE); CenterWithWires(*cx, *cy, "{RES}", poweredBefore, poweredAfter); break; } case ELEM_READ_ADC: { ElemReadAdc *r = &leaf->d.readAdc; CenterWithSpaces(*cx, *cy, r->name, poweredAfter, TRUE); CenterWithWires(*cx, *cy, "{READ ADC}", poweredBefore, poweredAfter); break; } case ELEM_SET_PWM: { ElemSetPwm *s = &leaf->d.setPwm; CenterWithSpaces(*cx, *cy, s->name, poweredAfter, TRUE); char l[50]; if(s->targetFreq >= 100000) { sprintf(l, "{PWM %d kHz}", (s->targetFreq+500)/1000); } else if(s->targetFreq >= 10000) { sprintf(l, "{PWM %.1f kHz}", s->targetFreq/1000.0); } else if(s->targetFreq >= 1000) { sprintf(l, "{PWM %.2f kHz}", s->targetFreq/1000.0); } else { sprintf(l, "{PWM %d Hz}", s->targetFreq); } CenterWithWires(*cx, *cy, l, poweredBefore, poweredAfter); break; } case ELEM_PERSIST: CenterWithSpaces(*cx, *cy, leaf->d.persist.var, poweredAfter, TRUE); CenterWithWires(*cx, *cy, "{PERSIST}", poweredBefore, poweredAfter); break; case ELEM_MOVE: { char top[256]; char bot[256]; ElemMove *m = &leaf->d.move; strcpy(top, "{ }"); if((strlen(m->dest) >= (POS_WIDTH - 9))) { memcpy(top + 1, m->dest, 3); memset(top + 4, '.', 3); memcpy(top + 7, m->dest + strlen(m->dest) - 3, 3); top[9 + 2] = ':'; top[9 + 3] = '='; } else { memcpy(top + 1, m->dest, strlen(m->dest)); top[strlen(m->dest) + 3] = ':'; top[strlen(m->dest) + 4] = '='; } strcpy(bot, "{ \x01MOV\x02}"); if (strlen(m->src) >= (POS_WIDTH - 9)) { memcpy(bot + 1, m->src, 3); memset(bot + 4, '.', 3); memcpy(bot + 7, m->src + strlen(m->src) - 2, 2); } else { memcpy(bot + 2, m->src, strlen(m->src)); } CenterWithSpaces(*cx, *cy, top, poweredAfter, FALSE); CenterWithWires(*cx, *cy, bot, poweredBefore, poweredAfter); break; } case ELEM_MASTER_RELAY: CenterWithWires(*cx, *cy, "{MASTER RLY}", poweredBefore, poweredAfter); break; case ELEM_SHIFT_REGISTER: { char bot[MAX_NAME_LEN+20]; memset(bot, ' ', sizeof(bot)); bot[0] = '{'; sprintf(bot+2, "%s0..%d", leaf->d.shiftRegister.name, leaf->d.shiftRegister.stages-1); bot[strlen(bot)] = ' '; bot[13] = '}'; bot[14] = '\0'; CenterWithSpaces(*cx, *cy, "{\x01SHIFT REG\x02 }", poweredAfter, FALSE); CenterWithWires(*cx, *cy, bot, poweredBefore, poweredAfter); break; } case ELEM_PIECEWISE_LINEAR: case ELEM_LOOK_UP_TABLE: { char top[MAX_NAME_LEN+20], bot[MAX_NAME_LEN+20]; char *dest, *index, *str; if(which == ELEM_PIECEWISE_LINEAR) { dest = leaf->d.piecewiseLinear.dest; index = leaf->d.piecewiseLinear.index; str = "PWL"; } else { dest = leaf->d.lookUpTable.dest; index = leaf->d.lookUpTable.index; str = "LUT"; } memset(top, ' ', sizeof(top)); top[0] = '{'; sprintf(top+2, "%s :=", dest); top[strlen(top)] = ' '; top[13] = '}'; top[14] = '\0'; CenterWithSpaces(*cx, *cy, top, poweredAfter, FALSE); memset(bot, ' ', sizeof(bot)); bot[0] = '{'; sprintf(bot+2, " %s[%s]", str, index); bot[strlen(bot)] = ' '; bot[13] = '}'; bot[14] = '\0'; CenterWithWires(*cx, *cy, bot, poweredBefore, poweredAfter); break; } case ELEM_COIL: { char buf[4]; ElemCoil *c = &leaf->d.coil; buf[0] = '('; if(c->negated) { buf[1] = '/'; } else if(c->setOnly) { buf[1] = 'S'; } else if(c->resetOnly) { buf[1] = 'R'; } else { buf[1] = ' '; } buf[2] = ')'; buf[3] = '\0'; CenterWithSpaces(*cx, *cy, c->name, poweredAfter, TRUE); CenterWithWires(*cx, *cy, buf, poweredBefore, poweredAfter); break; } case ELEM_DIV: case ELEM_MUL: case ELEM_SUB: case ELEM_ADD: { char top[POS_WIDTH*2-3+2]; char bot[POS_WIDTH*2-3]; memset(top, ' ', sizeof(top)-1); top[0] = '{'; memset(bot, ' ', sizeof(bot)-1); bot[0] = '{'; int lt = 1; if(which == ELEM_ADD) { memcpy(top+lt, "\x01""ADD\x02", 5); } else if(which == ELEM_SUB) { memcpy(top+lt, "\x01SUB\x02", 5); } else if(which == ELEM_MUL) { memcpy(top+lt, "\x01MUL\x02", 5); } else if(which == ELEM_DIV) { memcpy(top+lt, "\x01""DIV\x02", 5); } else oops(); lt += 7; memcpy(top+lt, leaf->d.math.dest, strlen(leaf->d.math.dest)); lt += strlen(leaf->d.math.dest) + 2; top[lt++] = ':'; top[lt++] = '='; int lb = 2; memcpy(bot+lb, leaf->d.math.op1, strlen(leaf->d.math.op1)); lb += strlen(leaf->d.math.op1) + 1; if(which == ELEM_ADD) { bot[lb++] = '+'; } else if(which == ELEM_SUB) { bot[lb++] = '-'; } else if(which == ELEM_MUL) { bot[lb++] = '*'; } else if(which == ELEM_DIV) { bot[lb++] = '/'; } else oops(); lb++; memcpy(bot+lb, leaf->d.math.op2, strlen(leaf->d.math.op2)); lb += strlen(leaf->d.math.op2); int l = max(lb, lt - 2); top[l+2] = '}'; top[l+3] = '\0'; bot[l] = '}'; bot[l+1] = '\0'; int extra = 2*POS_WIDTH - FormattedStrlen(top); PoweredText(poweredAfter); DrawChars(*cx + (extra/2), *cy + (POS_HEIGHT/2) - 1, top); CenterWithWiresWidth(*cx, *cy, bot, poweredBefore, poweredAfter, 2*POS_WIDTH); *cx += POS_WIDTH; break; } default: oops(); break; } *cx += POS_WIDTH; return poweredAfter; }