void GfxText32::Width(const char *text, int16 from, int16 len, GuiResourceId fontId, int16 &textWidth, int16 &textHeight, bool restoreFont) { uint16 curChar; textWidth = 0; textHeight = 0; GfxFont *font = _cache->getFont(fontId); if (font) { text += from; while (len--) { curChar = (*(const byte *)text++); switch (curChar) { case 0x0A: case 0x0D: case 0x9781: // this one is used by SQ4/japanese as line break as well textHeight = MAX<int16> (textHeight, font->getHeight()); break; case 0x7C: warning("Code processing isn't implemented in SCI32"); break; default: textHeight = MAX<int16> (textHeight, font->getHeight()); textWidth += font->getCharWidth(curChar); break; } } } }
int16 GfxText32::getTextWidth(const uint index, uint length) const { int16 width = 0; const char *text = _text.c_str() + index; GfxFont *font = _font; char currentChar = *text++; while (length > 0 && currentChar != '\0') { // Control codes are in the format `|<code><value>|` if (currentChar == '|') { // NOTE: Original engine code changed the global state of the // FontMgr here upon encountering any color, alignment, or // font control code. // To avoid requiring all callers to manually restore these // values on every call, we ignore control codes other than // font change (since alignment and color do not change the // width of characters), and simply update the font pointer // on stack instead of the member property font. currentChar = *text++; --length; if (length > 0 && currentChar == 'f') { GuiResourceId fontId = 0; do { currentChar = *text++; --length; fontId = fontId * 10 + currentChar - '0'; } while (length > 0 && *text >= '0' && *text <= '9'); if (length > 0) { font = _cache->getFont(fontId); } } // Forward through any more unknown control character data while (length > 0 && *text != '|') { ++text; --length; } if (length > 0) { ++text; --length; } } else { width += font->getCharWidth((unsigned char)currentChar); } if (length > 0) { currentChar = *text++; --length; } } return width; }
Font::Font(const GfxState *state, double size) { if ( size<1 ) kdDebug(30516) << "very small font size=" << size << endl; _pointSize = qRound(size); GfxRGB rgb; state->getFillRGB(&rgb); _color = toColor(rgb); GfxFont *font = state->getFont(); GString *gname = (font ? font->getName() : 0); QString name = (gname ? gname->getCString() : 0); // kdDebug(30516) << "font: " << name << endl; name = name.section('+', 1, 1).lower(); if ( name.isEmpty() ) name = "##dummy"; // dummy name init(name); }
void TipWnd::AddText(const char* str,DWORD color/* =0xFFFFFFFF */,float x/* =-1 */,float y/* =-1 */,eFontType type/* =DefaultType */,eFontSize size,bool autoEnter/* =true */,int maxWidth) { wchar_t out[256]; g_CTW(str,out); StringLine line(out,color,type,size,autoEnter); if (x!=-1 && y!=-1) { line.x = x; line.y = y; } if(maxWidth > 0) m_Width = maxWidth; else if (maxWidth == 0) { GfxFont* font = FontManager::sInstance().GetFont(FontAttr(line.fontType,line.size)); SIZE size = font->GetTextSize(out); if(size.cx > m_Width) m_Width = size.cx; } m_vStringLine.push_back(line); }
void updateFont(GfxState * state) { DiaFont *font; // without a font it wont make sense if (!state->getFont()) return; //FIXME: Dia is really unhappy about zero size fonts if (!(state->getFontSize() > 0.0)) return; GfxFont *f = state->getFont(); // instead of building the same font over and over again if (g_hash_table_lookup (this->font_map, f)) { ++font_map_hits; return; } DiaFontStyle style = (f->isSerif() ? DIA_FONT_SERIF : DIA_FONT_SANS) | (f->isItalic() ? DIA_FONT_ITALIC : DIA_FONT_NORMAL) // mapping all the font weights is just too much code for now ;) | (f->isBold () ? DIA_FONT_BOLD : DIA_FONT_WEIGHT_NORMAL); gchar *family = g_strdup (f->getFamily() ? f->getFamily()->getCString() : "sans"); // we are (not anymore) building the same font over and over again g_print ("Font 0x%08x: '%s' size=%g (* %g)\n", (int)f, family, state->getTransformedFontSize(), scale); // now try to make a fontname Dia/Pango can cope with // strip style postfix - we already have extracted the style bits above char *pf; if ((pf = strstr (family, " Regular")) != NULL) *pf = 0; if ((pf = strstr (family, " Bold")) != NULL) *pf = 0; if ((pf = strstr (family, " Italic")) != NULL) *pf = 0; if ((pf = strstr (family, " Oblique")) != NULL) *pf = 0; double *fm = f->getFontMatrix(); double fsize = state->getTransformedFontSize(); if (fm[0] != 0) fsize *= fabs(fm[3] / fm[0]); font = dia_font_new (family, style, fsize * scale / 0.8); g_hash_table_insert (this->font_map, f, font); g_free (family); }
void PreScanOutputDev::beginStringOp(GfxState *state) { int render; GfxFont *font; double m11, m12, m21, m22; Ref embRef; DisplayFontParam *dfp; GBool simpleTTF; render = state->getRender(); if (!(render & 1)) { check(state->getFillColorSpace(), state->getFillColor(), state->getFillOpacity(), state->getBlendMode()); } if ((render & 3) == 1 || (render & 3) == 2) { check(state->getStrokeColorSpace(), state->getStrokeColor(), state->getStrokeOpacity(), state->getBlendMode()); } font = state->getFont(); state->getFontTransMat(&m11, &m12, &m21, &m22); simpleTTF = fabs(m11 + m22) < 0.01 && m11 > 0 && fabs(m12) < 0.01 && fabs(m21) < 0.01 && fabs(state->getHorizScaling() - 1) < 0.001 && (font->getType() == fontTrueType || font->getType() == fontTrueTypeOT) && (font->getEmbeddedFontID(&embRef) || font->getExtFontFile() || (font->getName() && (dfp = globalParams->getDisplayFont(font)) && dfp->kind == displayFontTT)); if (simpleTTF) { //~ need to create a FoFiTrueType object, and check for a Unicode cmap } if (state->getRender() != 0 || !simpleTTF) { gdi = gFalse; } }
void GfxControls32::kernelTexteditChange(reg_t controlObject) { SciEvent curEvent; uint16 maxChars = 40; //readSelectorValue(_segMan, controlObject, SELECTOR(max)); // TODO reg_t textReference = readSelector(_segMan, controlObject, SELECTOR(text)); GfxFont *font = _cache->getFont(readSelectorValue(_segMan, controlObject, SELECTOR(font))); Common::String text; uint16 textSize; bool textChanged = false; bool textAddChar = false; Common::Rect rect; if (textReference.isNull()) error("kEditControl called on object that doesn't have a text reference"); text = _segMan->getString(textReference); // TODO: Finish this warning("kEditText ('%s')", text.c_str()); return; uint16 cursorPos = 0; //uint16 oldCursorPos = cursorPos; bool captureEvents = true; EventManager* eventMan = g_sci->getEventManager(); while (captureEvents) { curEvent = g_sci->getEventManager()->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK); if (curEvent.type == SCI_EVENT_NONE) { eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event } else { textSize = text.size(); switch (curEvent.type) { case SCI_EVENT_MOUSE_PRESS: // TODO: Implement mouse support for cursor change break; case SCI_EVENT_KEYBOARD: switch (curEvent.character) { case SCI_KEY_BACKSPACE: if (cursorPos > 0) { cursorPos--; text.deleteChar(cursorPos); textChanged = true; } eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event break; case SCI_KEY_DELETE: if (cursorPos < textSize) { text.deleteChar(cursorPos); textChanged = true; } eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event break; case SCI_KEY_HOME: // HOME cursorPos = 0; textChanged = true; eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event break; case SCI_KEY_END: // END cursorPos = textSize; textChanged = true; eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event break; case SCI_KEY_LEFT: // LEFT if (cursorPos > 0) { cursorPos--; textChanged = true; } eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event break; case SCI_KEY_RIGHT: // RIGHT if (cursorPos + 1 <= textSize) { cursorPos++; textChanged = true; } eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event break; case 3: // returned in SCI1 late and newer when Control - C is pressed if (curEvent.modifiers & SCI_KEYMOD_CTRL) { // Control-C erases the whole line cursorPos = 0; text.clear(); textChanged = true; } eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event break; case SCI_KEY_UP: case SCI_KEY_DOWN: case SCI_KEY_ENTER: case SCI_KEY_ESC: case SCI_KEY_TAB: case SCI_KEY_SHIFT_TAB: captureEvents = false; break; default: if ((curEvent.modifiers & SCI_KEYMOD_CTRL) && curEvent.character == 'c') { // Control-C in earlier SCI games (SCI0 - SCI1 middle) // Control-C erases the whole line cursorPos = 0; text.clear(); textChanged = true; } else if (curEvent.character > 31 && curEvent.character < 256 && textSize < maxChars) { // insert pressed character textAddChar = true; textChanged = true; } eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event break; } break; } } if (textChanged) { rect = g_sci->_gfxCompare->getNSRect(controlObject); if (textAddChar) { const char *textPtr = text.c_str(); // We check if we are really able to add the new char uint16 textWidth = 0; while (*textPtr) textWidth += font->getCharWidth((byte)*textPtr++); textWidth += font->getCharWidth(curEvent.character); // Does it fit? if (textWidth >= rect.width()) { return; } text.insertChar(curEvent.character, cursorPos++); // Note: the following checkAltInput call might make the text // too wide to fit, but SSCI fails to check that too. } reg_t hunkId = readSelector(_segMan, controlObject, SELECTOR(bitmap)); Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(controlObject); //texteditCursorErase(); // TODO: Cursor // Write back string _segMan->strcpy(textReference, text.c_str()); // Modify the buffer and show it warning("kernelTexteditChange"); #if 0 _text->createTextBitmap(controlObject, 0, 0, hunkId); _text->drawTextBitmap(0, 0, nsRect, controlObject); //texteditCursorDraw(rect, text.c_str(), cursorPos); // TODO: Cursor g_system->updateScreen(); #endif } else { // TODO: Cursor /* if (g_system->getMillis() >= _texteditBlinkTime) { _paint16->invertRect(_texteditCursorRect); _paint16->bitsShow(_texteditCursorRect); _texteditCursorVisible = !_texteditCursorVisible; texteditSetBlinkTime(); } */ } textAddChar = false; textChanged = false; g_sci->sleep(10); } // while }
reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) { reg_t stringObject = readSelector(_segMan, textObject, SELECTOR(text)); // The object in the text selector of the item can be either a raw string // or a Str object. In the latter case, we need to access the object's data // selector to get the raw string. if (_segMan->isHeapObject(stringObject)) stringObject = readSelector(_segMan, stringObject, SELECTOR(data)); Common::String text = _segMan->getString(stringObject); // HACK: The character offsets of the up and down arrow buttons are off by one // in GK1, for some unknown reason. Fix them here. if (text.size() == 1 && (text[0] == 29 || text[0] == 30)) { text.setChar(text[0] + 1, 0); } GuiResourceId fontId = readSelectorValue(_segMan, textObject, SELECTOR(font)); GfxFont *font = _cache->getFont(fontId); bool dimmed = readSelectorValue(_segMan, textObject, SELECTOR(dimmed)); int16 alignment = readSelectorValue(_segMan, textObject, SELECTOR(mode)); uint16 foreColor = readSelectorValue(_segMan, textObject, SELECTOR(fore)); uint16 backColor = readSelectorValue(_segMan, textObject, SELECTOR(back)); Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(textObject); uint16 width = nsRect.width() + 1; uint16 height = nsRect.height() + 1; // Limit rectangle dimensions, if requested if (maxWidth > 0) width = maxWidth; if (maxHeight > 0) height = maxHeight; // Upscale the coordinates/width if the fonts are already upscaled if (_screen->fontIsUpscaled()) { width = width * _screen->getDisplayWidth() / _screen->getWidth(); height = height * _screen->getDisplayHeight() / _screen->getHeight(); } int entrySize = width * height + BITMAP_HEADER_SIZE; reg_t memoryId = NULL_REG; if (prevHunk.isNull()) { memoryId = _segMan->allocateHunkEntry("TextBitmap()", entrySize); writeSelector(_segMan, textObject, SELECTOR(bitmap), memoryId); } else { memoryId = prevHunk; } byte *memoryPtr = _segMan->getHunkPointer(memoryId); if (prevHunk.isNull()) memset(memoryPtr, 0, BITMAP_HEADER_SIZE); byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; memset(bitmap, backColor, width * height); // Save totalWidth, totalHeight WRITE_LE_UINT16(memoryPtr, width); WRITE_LE_UINT16(memoryPtr + 2, height); int16 charCount = 0; uint16 curX = 0, curY = 0; const char *txt = text.c_str(); int16 textWidth, textHeight, totalHeight = 0, offsetX = 0, offsetY = 0; uint16 start = 0; // Calculate total text height while (*txt) { charCount = GetLongest(txt, width, font); if (charCount == 0) break; Width(txt, 0, (int16)strlen(txt), fontId, textWidth, textHeight, true); totalHeight += textHeight; txt += charCount; while (*txt == ' ') txt++; // skip over breaking spaces } txt = text.c_str(); // Draw text in buffer while (*txt) { charCount = GetLongest(txt, width, font); if (charCount == 0) break; Width(txt, start, charCount, fontId, textWidth, textHeight, true); switch (alignment) { case SCI_TEXT32_ALIGNMENT_RIGHT: offsetX = width - textWidth; break; case SCI_TEXT32_ALIGNMENT_CENTER: // Center text both horizontally and vertically offsetX = (width - textWidth) / 2; offsetY = (height - totalHeight) / 2; break; case SCI_TEXT32_ALIGNMENT_LEFT: offsetX = 0; break; default: warning("Invalid alignment %d used in TextBox()", alignment); } for (int i = 0; i < charCount; i++) { unsigned char curChar = txt[i]; font->drawToBuffer(curChar, curY + offsetY, curX + offsetX, foreColor, dimmed, bitmap, width, height); curX += font->getCharWidth(curChar); } curX = 0; curY += font->getHeight(); txt += charCount; while (*txt == ' ') txt++; // skip over breaking spaces } return memoryId; }
reg_t GfxControls32::kernelEditText(const reg_t controlObject) { SegManager *segMan = _segMan; TextEditor editor; reg_t textObject = readSelector(_segMan, controlObject, SELECTOR(text)); editor.text = _segMan->getString(textObject); editor.foreColor = readSelectorValue(_segMan, controlObject, SELECTOR(fore)); editor.backColor = readSelectorValue(_segMan, controlObject, SELECTOR(back)); editor.skipColor = readSelectorValue(_segMan, controlObject, SELECTOR(skip)); editor.fontId = readSelectorValue(_segMan, controlObject, SELECTOR(font)); editor.maxLength = readSelectorValue(_segMan, controlObject, SELECTOR(width)); editor.bitmap = readSelector(_segMan, controlObject, SELECTOR(bitmap)); editor.cursorCharPosition = 0; editor.cursorIsDrawn = false; editor.borderColor = readSelectorValue(_segMan, controlObject, SELECTOR(borderColor)); reg_t titleObject = readSelector(_segMan, controlObject, SELECTOR(title)); int16 titleHeight = 0; GuiResourceId titleFontId = readSelectorValue(_segMan, controlObject, SELECTOR(titleFont)); if (!titleObject.isNull()) { GfxFont *titleFont = _gfxCache->getFont(titleFontId); titleHeight += _gfxText32->scaleUpHeight(titleFont->getHeight()) + 1; if (editor.borderColor != -1) { titleHeight += 2; } } int16 width = 0; int16 height = titleHeight; GfxFont *editorFont = _gfxCache->getFont(editor.fontId); height += _gfxText32->scaleUpHeight(editorFont->getHeight()) + 1; _gfxText32->setFont(editor.fontId); int16 emSize = _gfxText32->getCharWidth('M', true); width += editor.maxLength * emSize + 1; if (editor.borderColor != -1) { width += 4; height += 2; } Common::Rect editorPlaneRect(width, height); editorPlaneRect.translate(readSelectorValue(_segMan, controlObject, SELECTOR(x)), readSelectorValue(_segMan, controlObject, SELECTOR(y))); reg_t planeObj = readSelector(_segMan, controlObject, SELECTOR(plane)); Plane *sourcePlane = g_sci->_gfxFrameout->getVisiblePlanes().findByObject(planeObj); if (sourcePlane == nullptr) { sourcePlane = g_sci->_gfxFrameout->getPlanes().findByObject(planeObj); if (sourcePlane == nullptr) { error("Could not find plane %04x:%04x", PRINT_REG(planeObj)); } } editorPlaneRect.translate(sourcePlane->_gameRect.left, sourcePlane->_gameRect.top); editor.textRect = Common::Rect(2, titleHeight + 2, width - 1, height - 1); editor.width = width; if (editor.bitmap.isNull()) { TextAlign alignment = (TextAlign)readSelectorValue(_segMan, controlObject, SELECTOR(mode)); if (titleObject.isNull()) { bool dimmed = readSelectorValue(_segMan, controlObject, SELECTOR(dimmed)); editor.bitmap = _gfxText32->createFontBitmap(width, height, editor.textRect, editor.text, editor.foreColor, editor.backColor, editor.skipColor, editor.fontId, alignment, editor.borderColor, dimmed, true, false); } else { error("Titled bitmaps are not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!"); } } drawCursor(editor); Plane *plane = new Plane(editorPlaneRect, kPlanePicTransparent); plane->changePic(); g_sci->_gfxFrameout->addPlane(*plane); CelInfo32 celInfo; celInfo.type = kCelTypeMem; celInfo.bitmap = editor.bitmap; ScreenItem *screenItem = new ScreenItem(plane->_object, celInfo, Common::Point(), ScaleInfo()); plane->_screenItemList.add(screenItem); // frameOut must be called after the screen item is // created, and before it is updated at the end of the // event loop, otherwise it has both created and updated // flags set which crashes the engine (it runs updates // before creations) g_sci->_gfxFrameout->frameOut(true); EventManager *eventManager = g_sci->getEventManager(); bool clearTextOnInput = true; bool textChanged = false; for (;;) { // We peek here because the last event needs to be allowed to // dispatch a second time to the normal event handling system. // In the actual engine, the event is always consumed and then // the last event just gets posted back to the event manager for // reprocessing, but instead, we only remove the event from the // queue *after* we have determined it is not a defocusing event const SciEvent event = eventManager->getSciEvent(SCI_EVENT_ANY | SCI_EVENT_PEEK); bool focused = true; // Original engine did not have a QUIT event but we have to handle it if (event.type == SCI_EVENT_QUIT) { focused = false; break; } else if (event.type == SCI_EVENT_MOUSE_PRESS && !editorPlaneRect.contains(event.mousePosSci)) { focused = false; } else if (event.type == SCI_EVENT_KEYBOARD) { switch (event.character) { case SCI_KEY_ESC: case SCI_KEY_UP: case SCI_KEY_DOWN: case SCI_KEY_TAB: case SCI_KEY_SHIFT_TAB: case SCI_KEY_ENTER: focused = false; break; } } if (!focused) { break; } // Consume the event now that we know it is not one of the // defocusing events above if (event.type != SCI_EVENT_NONE) eventManager->getSciEvent(SCI_EVENT_ANY); // NOTE: In the original engine, the font and bitmap were // reset here on each iteration through the loop, but it // doesn't seem like this should be necessary since // control is not yielded back to the VM until input is // received, which means there is nothing that could modify // the GfxText32's state with a different font in the // meantime bool shouldDeleteChar = false; bool shouldRedrawText = false; uint16 lastCursorPosition = editor.cursorCharPosition; if (event.type == SCI_EVENT_KEYBOARD) { switch (event.character) { case SCI_KEY_LEFT: clearTextOnInput = false; if (editor.cursorCharPosition > 0) { --editor.cursorCharPosition; } break; case SCI_KEY_RIGHT: clearTextOnInput = false; if (editor.cursorCharPosition < editor.text.size()) { ++editor.cursorCharPosition; } break; case SCI_KEY_HOME: clearTextOnInput = false; editor.cursorCharPosition = 0; break; case SCI_KEY_END: clearTextOnInput = false; editor.cursorCharPosition = editor.text.size(); break; case SCI_KEY_INSERT: clearTextOnInput = false; // Redrawing also changes the cursor rect to // reflect the new insertion mode shouldRedrawText = true; _overwriteMode = !_overwriteMode; break; case SCI_KEY_DELETE: clearTextOnInput = false; if (editor.cursorCharPosition < editor.text.size()) { shouldDeleteChar = true; } break; case SCI_KEY_BACKSPACE: clearTextOnInput = false; shouldDeleteChar = true; if (editor.cursorCharPosition > 0) { --editor.cursorCharPosition; } break; case SCI_KEY_ETX: editor.text.clear(); editor.cursorCharPosition = 0; shouldRedrawText = true; break; default: { if (event.character >= 20 && event.character < 257) { if (clearTextOnInput) { clearTextOnInput = false; editor.text.clear(); } if ( (_overwriteMode && editor.cursorCharPosition < editor.maxLength) || (editor.text.size() < editor.maxLength && _gfxText32->getCharWidth(event.character, true) + _gfxText32->getStringWidth(editor.text) < editor.textRect.width()) ) { if (_overwriteMode && editor.cursorCharPosition < editor.text.size()) { editor.text.setChar(event.character, editor.cursorCharPosition); } else { editor.text.insertChar(event.character, editor.cursorCharPosition); } ++editor.cursorCharPosition; shouldRedrawText = true; } } } } } if (shouldDeleteChar) { shouldRedrawText = true; if (editor.cursorCharPosition < editor.text.size()) { editor.text.deleteChar(editor.cursorCharPosition); } } if (shouldRedrawText) { eraseCursor(editor); _gfxText32->erase(editor.textRect, true); _gfxText32->drawTextBox(editor.text); drawCursor(editor); textChanged = true; screenItem->_updated = g_sci->_gfxFrameout->getScreenCount(); } else if (editor.cursorCharPosition != lastCursorPosition) { eraseCursor(editor); drawCursor(editor); screenItem->_updated = g_sci->_gfxFrameout->getScreenCount(); } else { flashCursor(editor); screenItem->_updated = g_sci->_gfxFrameout->getScreenCount(); } g_sci->_gfxFrameout->frameOut(true); g_sci->getSciDebugger()->onFrame(); g_sci->_gfxFrameout->throttle(); } g_sci->_gfxFrameout->deletePlane(*plane); if (readSelectorValue(segMan, controlObject, SELECTOR(frameOut))) { g_sci->_gfxFrameout->frameOut(true); } _segMan->freeBitmap(editor.bitmap); if (textChanged) { editor.text.trim(); SciArray &string = *_segMan->lookupArray(textObject); string.fromString(editor.text); } return make_reg(0, textChanged); }
void GfxControls32::kernelTexteditChange(reg_t controlObject) { SciEvent curEvent; uint16 maxChars = readSelectorValue(_segMan, controlObject, SELECTOR(max)); reg_t textReference = readSelector(_segMan, controlObject, SELECTOR(text)); GfxFont *font = _cache->getFont(readSelectorValue(_segMan, controlObject, SELECTOR(font))); Common::String text; uint16 textSize; bool textChanged = false; bool textAddChar = false; Common::Rect rect; if (textReference.isNull()) error("kEditControl called on object that doesnt have a text reference"); text = _segMan->getString(textReference); // TODO: Finish this, add a loop etc warning("kEditText ('%s')", text.c_str()); return; uint16 cursorPos = 0; //uint16 oldCursorPos = cursorPos; curEvent = g_sci->getEventManager()->getSciEvent(SCI_EVENT_KEYBOARD); if (curEvent.type != SCI_EVENT_NONE) { textSize = text.size(); switch (curEvent.type) { case SCI_EVENT_MOUSE_PRESS: // TODO: Implement mouse support for cursor change break; case SCI_EVENT_KEYBOARD: switch (curEvent.data) { case SCI_KEY_BACKSPACE: if (cursorPos > 0) { cursorPos--; text.deleteChar(cursorPos); textChanged = true; } break; case SCI_KEY_DELETE: if (cursorPos < textSize) { text.deleteChar(cursorPos); textChanged = true; } break; case SCI_KEY_HOME: // HOME cursorPos = 0; textChanged = true; break; case SCI_KEY_END: // END cursorPos = textSize; textChanged = true; break; case SCI_KEY_LEFT: // LEFT if (cursorPos > 0) { cursorPos--; textChanged = true; } break; case SCI_KEY_RIGHT: // RIGHT if (cursorPos + 1 <= textSize) { cursorPos++; textChanged = true; } break; case 3: // returned in SCI1 late and newer when Control - C is pressed if (curEvent.modifiers & SCI_KEYMOD_CTRL) { // Control-C erases the whole line cursorPos = 0; text.clear(); textChanged = true; } break; default: if ((curEvent.modifiers & SCI_KEYMOD_CTRL) && curEvent.data == 99) { // Control-C in earlier SCI games (SCI0 - SCI1 middle) // Control-C erases the whole line cursorPos = 0; text.clear(); textChanged = true; } else if (curEvent.data > 31 && curEvent.data < 256 && textSize < maxChars) { // insert pressed character textAddChar = true; textChanged = true; } break; } break; } } if (textChanged) { rect = g_sci->_gfxCompare->getNSRect(controlObject); if (textAddChar) { const char *textPtr = text.c_str(); // We check if we are really able to add the new char uint16 textWidth = 0; while (*textPtr) textWidth += font->getCharWidth((byte)*textPtr++); textWidth += font->getCharWidth(curEvent.data); // Does it fit? if (textWidth >= rect.width()) { return; } text.insertChar(curEvent.data, cursorPos++); // Note: the following checkAltInput call might make the text // too wide to fit, but SSCI fails to check that too. } // TODO: Cursor /* texteditCursorErase(); _paint16->eraseRect(rect); _text16->Box(text.c_str(), false, rect, SCI_TEXT16_ALIGNMENT_LEFT, -1); _paint16->bitsShow(rect); texteditCursorDraw(rect, text.c_str(), cursorPos); */ // Write back string _segMan->strcpy(textReference, text.c_str()); } else { // TODO: Cursor /* if (g_system->getMillis() >= _texteditBlinkTime) { _paint16->invertRect(_texteditCursorRect); _paint16->bitsShow(_texteditCursorRect); _texteditCursorVisible = !_texteditCursorVisible; texteditSetBlinkTime(); } */ } }
/*! * \brief Draw a string to _Textobj * * To get objects more similar to what we had during export we * should probably use TextOutputDev. It reassembles strings * based on their position on the page. Or maybe Dia/cairo should * stop realigning single glyphs in it's output? * * \todo Check alignment options - it's just guessed yet. */ void DiaOutputDev::drawString(GfxState *state, GooString *s) { Color text_color = this->fill_color; int len = s->getLength(); DiaObject *obj; gchar *utf8 = NULL; DiaFont *font; // ignore empty strings if (len == 0) return; // get the font if (!state->getFont()) return; if (!(state->getFontSize() > 0.0)) return; font = (DiaFont *)g_hash_table_lookup (this->font_map, state->getFont()); // we have to decode the string data first { GfxFont *f = state->getFont(); char *p = s->getCString(); CharCode code; int j = 0, m, n; utf8 = g_new (gchar, len * 6 + 1); Unicode *u; int uLen; double dx, dy, ox, oy; while (len > 0) { n = f->getNextChar(p, len, &code, &u, &uLen, &dx, &dy, &ox, &oy); p += n; len -= n; m = g_unichar_to_utf8 (u[0], &utf8[j]); j += m; } utf8[j] = '\0'; } // check for invisible text -- this is used by Acrobat Capture if (state->getRender() == 3) text_color.alpha = 0.0; // not sure how state->getLineX() is related, it's 0 in my test cases double tx = state->getCurX(); double ty = state->getCurY(); int rot = state->getRotate(); if (rot == 0) obj = create_standard_text (tx * scale, page_height - ty * scale); else /* XXX: at least for rot==90 */ obj = create_standard_text (ty * scale, tx * scale); //not applyStyle (obj, TEXT); GPtrArray *plist = g_ptr_array_new (); // the "text" property is special, it must be initialized with text // attributes, too. So here it comes first to avoid overwriting // the other values with defaults. prop_list_add_text (plist, "text", utf8); prop_list_add_font (plist, "text_font", font); prop_list_add_text_colour (plist, &text_color); prop_list_add_enum (plist, "text_alignment", this->alignment); prop_list_add_fontsize (plist, "text_height", state->getTransformedFontSize() * scale / 0.8); obj->ops->set_props (obj, plist); prop_list_free (plist); g_free (utf8); addObject (obj); }
void GfxFrameout::kernelFrameout() { if (g_sci->_robotDecoder->isVideoLoaded()) { bool skipVideo = false; RobotDecoder *videoDecoder = g_sci->_robotDecoder; uint16 x = videoDecoder->getPos().x; uint16 y = videoDecoder->getPos().y; if (videoDecoder->hasDirtyPalette()) videoDecoder->setSystemPalette(); while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { if (videoDecoder->needsUpdate()) { const Graphics::Surface *frame = videoDecoder->decodeNextFrame(); if (frame) { g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h); if (videoDecoder->hasDirtyPalette()) videoDecoder->setSystemPalette(); g_system->updateScreen(); } } Common::Event event; while (g_system->getEventManager()->pollEvent(event)) { if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP) skipVideo = true; } g_system->delayMillis(10); } return; } _palette->palVaryUpdate(); for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); it++) { reg_t planeObject = it->object; uint16 planeLastPriority = it->lastPriority; // Update priority here, sq6 sets it w/o UpdatePlane uint16 planePriority = it->priority = readSelectorValue(_segMan, planeObject, SELECTOR(priority)); it->lastPriority = planePriority; if (planePriority == 0xffff) { // Plane currently not meant to be shown // If plane was shown before, delete plane rect if (planePriority != planeLastPriority) _paint32->fillRect(it->planeRect, 0); continue; } if (it->planeBack) _paint32->fillRect(it->planeRect, it->planeBack); GuiResourceId planeMainPictureId = it->pictureId; _coordAdjuster->pictureSetDisplayArea(it->planeRect); _palette->drewPicture(planeMainPictureId); FrameoutList itemList; // Copy screen items of the current frame to the list of items to be drawn for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) { reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane)); if (planeObject == itemPlane) { kernelUpdateScreenItem((*listIterator)->object); // TODO: Why is this necessary? itemList.push_back(*listIterator); } } for (PlanePictureList::iterator pictureIt = _planePictures.begin(); pictureIt != _planePictures.end(); pictureIt++) { if (pictureIt->object == planeObject) { GfxPicture *planePicture = pictureIt->picture; // Allocate memory for picture cels pictureIt->pictureCels = new FrameoutEntry[planePicture->getSci32celCount()]; // Add following cels to the itemlist FrameoutEntry *picEntry = pictureIt->pictureCels; int planePictureCels = planePicture->getSci32celCount(); for (int pictureCelNr = 0; pictureCelNr < planePictureCels; pictureCelNr++) { picEntry->celNo = pictureCelNr; picEntry->object = NULL_REG; picEntry->picture = planePicture; picEntry->y = planePicture->getSci32celY(pictureCelNr); picEntry->x = planePicture->getSci32celX(pictureCelNr); picEntry->picStartX = pictureIt->startX; picEntry->priority = planePicture->getSci32celPriority(pictureCelNr); itemList.push_back(picEntry); picEntry++; } } } // Now sort our itemlist Common::sort(itemList.begin(), itemList.end(), sortHelper); // warning("Plane %s", _segMan->getObjectName(planeObject)); for (FrameoutList::iterator listIterator = itemList.begin(); listIterator != itemList.end(); listIterator++) { FrameoutEntry *itemEntry = *listIterator; if (itemEntry->object.isNull()) { // Picture cel data itemEntry->y = ((itemEntry->y * _screen->getHeight()) / scriptsRunningHeight); itemEntry->x = ((itemEntry->x * _screen->getWidth()) / scriptsRunningWidth); itemEntry->picStartX = ((itemEntry->picStartX * _screen->getWidth()) / scriptsRunningWidth); // Out of view int16 pictureCelStartX = itemEntry->picStartX + itemEntry->x; int16 pictureCelEndX = pictureCelStartX + itemEntry->picture->getSci32celWidth(itemEntry->celNo); int16 planeStartX = it->planeOffsetX; int16 planeEndX = planeStartX + it->planeRect.width(); if (pictureCelEndX < planeStartX) continue; if (pictureCelStartX > planeEndX) continue; int16 pictureOffsetX = it->planeOffsetX; int16 pictureX = itemEntry->x; if ((it->planeOffsetX) || (itemEntry->picStartX)) { if (it->planeOffsetX <= itemEntry->picStartX) { pictureX += itemEntry->picStartX - it->planeOffsetX; pictureOffsetX = 0; } else { pictureOffsetX = it->planeOffsetX - itemEntry->picStartX; } } itemEntry->picture->drawSci32Vga(itemEntry->celNo, pictureX, itemEntry->y, pictureOffsetX, it->planePictureMirrored); // warning("picture cel %d %d", itemEntry->celNo, itemEntry->priority); } else if (itemEntry->viewId != 0xFFFF) { GfxView *view = _cache->getView(itemEntry->viewId); // warning("view %s %04x:%04x", _segMan->getObjectName(itemEntry->object), PRINT_REG(itemEntry->object)); if (view->isSci2Hires()) { int16 dummyX = 0; _screen->adjustToUpscaledCoordinates(itemEntry->y, itemEntry->x); _screen->adjustToUpscaledCoordinates(itemEntry->z, dummyX); } else if (getSciVersion() == SCI_VERSION_2_1) { itemEntry->y = (itemEntry->y * _screen->getHeight()) / scriptsRunningHeight; itemEntry->x = (itemEntry->x * _screen->getWidth()) / scriptsRunningWidth; itemEntry->z = (itemEntry->z * _screen->getHeight()) / scriptsRunningHeight; } // Adjust according to current scroll position itemEntry->x -= it->planeOffsetX; uint16 useInsetRect = readSelectorValue(_segMan, itemEntry->object, SELECTOR(useInsetRect)); if (useInsetRect) { itemEntry->celRect.top = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inTop)); itemEntry->celRect.left = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inLeft)); itemEntry->celRect.bottom = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inBottom)) + 1; itemEntry->celRect.right = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inRight)) + 1; if (view->isSci2Hires()) { _screen->adjustToUpscaledCoordinates(itemEntry->celRect.top, itemEntry->celRect.left); _screen->adjustToUpscaledCoordinates(itemEntry->celRect.bottom, itemEntry->celRect.right); } itemEntry->celRect.translate(itemEntry->x, itemEntry->y); // TODO: maybe we should clip the cels rect with this, i'm not sure // the only currently known usage is game menu of gk1 } else { if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128)) view->getCelRect(itemEntry->loopNo, itemEntry->celNo, itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->celRect); else view->getCelScaledRect(itemEntry->loopNo, itemEntry->celNo, itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->scaleX, itemEntry->scaleY, itemEntry->celRect); Common::Rect nsRect = itemEntry->celRect; // Translate back to actual coordinate within scrollable plane nsRect.translate(it->planeOffsetX, 0); if (view->isSci2Hires()) { _screen->adjustBackUpscaledCoordinates(nsRect.top, nsRect.left); _screen->adjustBackUpscaledCoordinates(nsRect.bottom, nsRect.right); } else if (getSciVersion() == SCI_VERSION_2_1) { nsRect.top = (nsRect.top * scriptsRunningHeight) / _screen->getHeight(); nsRect.left = (nsRect.left * scriptsRunningWidth) / _screen->getWidth(); nsRect.bottom = (nsRect.bottom * scriptsRunningHeight) / _screen->getHeight(); nsRect.right = (nsRect.right * scriptsRunningWidth) / _screen->getWidth(); } writeSelectorValue(_segMan, itemEntry->object, SELECTOR(nsLeft), nsRect.left); writeSelectorValue(_segMan, itemEntry->object, SELECTOR(nsTop), nsRect.top); writeSelectorValue(_segMan, itemEntry->object, SELECTOR(nsRight), nsRect.right); writeSelectorValue(_segMan, itemEntry->object, SELECTOR(nsBottom), nsRect.bottom); } int16 screenHeight = _screen->getHeight(); int16 screenWidth = _screen->getWidth(); if (view->isSci2Hires()) { screenHeight = _screen->getDisplayHeight(); screenWidth = _screen->getDisplayWidth(); } if (itemEntry->celRect.bottom < 0 || itemEntry->celRect.top >= screenHeight) continue; if (itemEntry->celRect.right < 0 || itemEntry->celRect.left >= screenWidth) continue; Common::Rect clipRect, translatedClipRect; clipRect = itemEntry->celRect; if (view->isSci2Hires()) { clipRect.clip(it->upscaledPlaneClipRect); translatedClipRect = clipRect; translatedClipRect.translate(it->upscaledPlaneRect.left, it->upscaledPlaneRect.top); } else { clipRect.clip(it->planeClipRect); translatedClipRect = clipRect; translatedClipRect.translate(it->planeRect.left, it->planeRect.top); } if (!clipRect.isEmpty()) { if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128)) view->draw(itemEntry->celRect, clipRect, translatedClipRect, itemEntry->loopNo, itemEntry->celNo, 255, 0, view->isSci2Hires()); else view->drawScaled(itemEntry->celRect, clipRect, translatedClipRect, itemEntry->loopNo, itemEntry->celNo, 255, itemEntry->scaleX, itemEntry->scaleY); } } else { // Most likely a text entry // This draws text the "SCI0-SCI11" way. In SCI2, text is prerendered in kCreateTextBitmap // TODO: rewrite this the "SCI2" way (i.e. implement the text buffer to draw inside kCreateTextBitmap) if (lookupSelector(_segMan, itemEntry->object, SELECTOR(text), NULL, NULL) == kSelectorVariable) { reg_t stringObject = readSelector(_segMan, itemEntry->object, SELECTOR(text)); // The object in the text selector of the item can be either a raw string // or a Str object. In the latter case, we need to access the object's data // selector to get the raw string. if (_segMan->isHeapObject(stringObject)) stringObject = readSelector(_segMan, stringObject, SELECTOR(data)); Common::String text = _segMan->getString(stringObject); GfxFont *font = _cache->getFont(readSelectorValue(_segMan, itemEntry->object, SELECTOR(font))); bool dimmed = readSelectorValue(_segMan, itemEntry->object, SELECTOR(dimmed)); uint16 foreColor = readSelectorValue(_segMan, itemEntry->object, SELECTOR(fore)); itemEntry->y = ((itemEntry->y * _screen->getHeight()) / scriptsRunningHeight); itemEntry->x = ((itemEntry->x * _screen->getWidth()) / scriptsRunningWidth); uint16 startX = itemEntry->x + it->planeRect.left; uint16 curY = itemEntry->y + it->planeRect.top; const char *txt = text.c_str(); // HACK. The plane sometimes doesn't contain the correct width. This // hack breaks the dialog options when speaking with Grace, but it's // the best we got up to now. This happens because of the unimplemented // kTextWidth function in SCI32. // TODO: Remove this once kTextWidth has been implemented. uint16 w = it->planeRect.width() >= 20 ? it->planeRect.width() : _screen->getWidth() - 10; int16 charCount; // Upscale the coordinates/width if the fonts are already upscaled if (_screen->fontIsUpscaled()) { startX = startX * _screen->getDisplayWidth() / _screen->getWidth(); curY = curY * _screen->getDisplayHeight() / _screen->getHeight(); w = w * _screen->getDisplayWidth() / _screen->getWidth(); } while (*txt) { charCount = GetLongest(txt, w, font); if (charCount == 0) break; uint16 curX = startX; for (int i = 0; i < charCount; i++) { unsigned char curChar = txt[i]; font->draw(curChar, curY, curX, foreColor, dimmed); curX += font->getCharWidth(curChar); } curY += font->getHeight(); txt += charCount; while (*txt == ' ') txt++; // skip over breaking spaces } } } } for (PlanePictureList::iterator pictureIt = _planePictures.begin(); pictureIt != _planePictures.end(); pictureIt++) { if (pictureIt->object == planeObject) { delete[] pictureIt->pictureCels; pictureIt->pictureCels = 0; } } } _screen->copyToScreen(); g_sci->getEngineState()->_throttleTrigger = true; }
void TipWnd::Render() { if (m_Show && !m_vStringLine.empty()) { //先绘制tip窗口 hgeQuad quad; quad.v[0].x = m_OffX - m_OffLeft; quad.v[0].y = m_OffY - m_OffTop; quad.v[0].tx = 0; quad.v[0].ty = 0; quad.v[1].x = m_OffX+m_Width + m_OffRight; quad.v[1].y = m_OffY - m_OffTop; quad.v[1].tx = 1; quad.v[1].ty = 0; quad.v[2].x = m_OffX+m_Width + m_OffRight; quad.v[2].y = m_OffY+m_Height + m_OffBottom; quad.v[2].tx = 1; quad.v[2].ty = 1; quad.v[3].x = m_OffX - m_OffLeft; quad.v[3].y = m_OffY+m_Height + m_OffBottom; quad.v[3].tx = 0; quad.v[3].ty = 1; for (int i=0; i<4; i++) { quad.v[i].col = 0xAF484848; quad.v[i].z = 0.5; } quad.blend = BLEND_DEFAULT_Z; quad.tex = 0; App::sInstance().GetHGE()->Gfx_RenderQuad(&quad); //绘制文字 m_LastX = m_OffX; m_LastY = m_OffY; for (VStringLine::iterator it=m_vStringLine.begin(); it!=m_vStringLine.end(); it++) { GfxFont* font = FontManager::sInstance().GetFont(FontAttr(it->fontType,it->size)); DWORD color = font->GetColor(); font->SetColor(it->color); //从指定位置绘制文字 if(it->x!=-1 && it->y!=-1) { m_LastX = m_OffX + it->x; m_LastY = m_OffY + it->y; int width = it->x; int height = it->y; //采用一个一个字符绘制来控制文本宽度不超过tip窗口最大宽度 SIZE size = font->GetTextSize((*it).str.c_str()); if(size.cx + it->x <= m_Width) { if(height + size.cy >= m_Height) m_Height += size.cy; font->Render(m_LastX,m_LastY,(*it).str.c_str()); if(it->autoEnter) { m_LastY += it->size; m_LastX = m_OffX; height += size.cy; width = 0; if(height+size.cy >= m_Height) m_Height += size.cy; } else { m_LastX += size.cx; width += size.cx; height += size.cy; } } else { SIZE charSize; wchar_t temp[256]; const wchar_t* oneChar = (*it).str.c_str(); while (*oneChar) { memcpy(temp,oneChar,2); temp[1] = '\0'; charSize = font->GetTextSize(temp); if(width + charSize.cx <= m_Width) { if (height + charSize.cy >= m_Height) { m_Height += charSize.cy; } font->Render(m_LastX,m_LastY,temp); m_LastX += charSize.cx; width += charSize.cx; } else //换行 { width = 0; height += charSize.cy; if(height + charSize.cy >= m_Height) { m_Height += charSize.cy; } m_LastY += charSize.cy; m_LastX = m_OffX; font->Render(m_LastX,m_LastY,temp); m_LastX += charSize.cx; width += charSize.cx; } oneChar++; } if(it->autoEnter) { m_LastY += it->size; m_LastX = m_OffX; height += size.cy; } } } //没有指定位置,继续上次绘制位置来绘制文本 else if (it->x == -1 && it->y == -1) { int width = m_LastX - m_OffX; int height = m_LastY - m_OffY; SIZE size = font->GetTextSize((*it).str.c_str()); if (size.cx + width <= m_Width) { if(size.cy + height >= m_Height) m_Height += size.cy; font->Render(m_LastX,m_LastY,(*it).str.c_str()); if (it->autoEnter) { m_LastY += size.cy; m_LastX = m_OffX; width = 0; height += size.cy; if(height + size.cy >= m_Height) m_Height += size.cy; } else m_LastX += size.cx; } else { SIZE charSize; wchar_t temp[256]; const wchar_t* oneChar = (*it).str.c_str(); while (*oneChar) { memcpy(temp,oneChar,2); temp[1] = '\0'; charSize = font->GetTextSize(temp); if(width + charSize.cx <= m_Width) { if (height + charSize.cy >= m_Height) { m_Height += charSize.cy; } font->Render(m_LastX,m_LastY,temp); m_LastX += charSize.cx; width += charSize.cx; } else //换行 { width = 0; height += charSize.cy; if(height + charSize.cy >= m_Height) { m_Height += charSize.cy; } m_LastY += charSize.cy; m_LastX = m_OffX; font->Render(m_LastX,m_LastY,temp); m_LastX += charSize.cx; width += charSize.cx; } oneChar++; } if(it->autoEnter) { m_LastY += it->size; m_LastX = m_OffX; height += size.cy; } } } font->SetColor(color); } } }
void GameDisplayDlg::Render() { if(m_xItemList.empty()) { return; } if(m_rcClient.left == m_rcClient.right || m_rcClient.top == m_rcClient.bottom) { return; } hgeResourceManager* pResMgr = g_pResMgr; HTEXTURE tex = 0; { // draw bk tex = pResMgr->GetTexture("bmcolor"); if(tex) { m_pRender->SetTexture(tex); m_pRender->SetTextureRect(0, 0, m_rcClient.right - m_rcClient.left, m_rcClient.bottom - m_rcClient.top); m_pRender->Render(m_rcClient.left, m_rcClient.top); } } int nDrawX = 0; int nDrawY = 0; { // render strings std::list<DisplayItem*>::const_iterator begIter = m_xItemList.begin(); std::list<DisplayItem*>::const_iterator endIter = m_xItemList.end(); for(begIter; begIter != endIter; ++begIter) { DisplayItem* pDisplayItem = *begIter; if(pDisplayItem) { GfxFont* pFont = pDisplayItem->pFont; if(SHOW_STRING == pDisplayItem->nShowType) { if(NULL == pFont) { // default font pFont = AfxGetFont(); } pFont->SetColor(ARGB_WHITE); if(0 != pDisplayItem->dwColor) { pFont->SetColor(pDisplayItem->dwColor); } nDrawX = RELATIVE_X(pDisplayItem->nPosX); nDrawY = RELATIVE_Y(pDisplayItem->nPosY); pFont->Print((float)nDrawX, (float)nDrawY, pDisplayItem->xText.c_str()); } } } } }