📄 text.c
字号:
/*
** $Id: text.c,v 1.48 2004/10/06 00:39:04 snig Exp $
**
** The Text Support of GDI.
**
** Copyright (C) 2000 ~ 2002 Wei Yongming.
** Copyright (C) 2003 Feynman Software.
**
** Current maintainer: Wei Yongming.
**
** Create date: 2000.4.19
*/
/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
** TODO:
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#include "minigui.h"
#include "gdi.h"
#include "window.h"
#include "cliprect.h"
#include "gal.h"
#include "internals.h"
#include "ctrlclass.h"
#include "dc.h"
#include "drawtext.h"
#include "cursor.h"
extern BOOL dc_GenerateECRgn (PDC pdc, BOOL fForce);
int GUIAPI GetFontHeight (HDC hdc)
{
PDC pdc = dc_HDC2PDC(hdc);
return pdc->pLogFont->size;
}
int GUIAPI GetMaxFontWidth (HDC hdc)
{
PDC pdc = dc_HDC2PDC(hdc);
DEVFONT* sbc_devfont = pdc->pLogFont->sbc_devfont;
DEVFONT* mbc_devfont = pdc->pLogFont->mbc_devfont;
int sbc_max_width = (*sbc_devfont->font_ops->get_max_width) (pdc->pLogFont, sbc_devfont);
int mbc_max_width = 0;
if (mbc_devfont)
mbc_max_width = (*mbc_devfont->font_ops->get_max_width) (pdc->pLogFont, mbc_devfont);
return (sbc_max_width > mbc_max_width) ? sbc_max_width : mbc_max_width;
}
void GUIAPI GetTextExtent (HDC hdc, const char* spText, int len, SIZE* pSize)
{
PDC pdc;
pdc = dc_HDC2PDC(hdc);
if (len < 0) len = strlen (spText);
gdi_get_TextOut_extent (pdc, pdc->pLogFont, spText, len, pSize);
}
void GUIAPI GetTabbedTextExtent (HDC hdc, const char* spText, int len, SIZE* pSize)
{
PDC pdc;
pdc = dc_HDC2PDC(hdc);
if (len < 0) len = strlen (spText);
gdi_get_TabbedTextOut_extent (pdc, pdc->pLogFont, pdc->tabstop,
spText, len, pSize, NULL);
}
void GUIAPI GetLastTextOutPos (HDC hdc, POINT* pt)
{
PDC pdc;
pdc = dc_HDC2PDC(hdc);
*pt = pdc->CurTextPos;
}
int GUIAPI TextOutLen (HDC hdc, int x, int y, const char* spText, int len)
{
PCLIPRECT pClipRect;
PDC pdc;
RECT rcOutput;
SIZE size;
if (!spText || len == 0) return 0;
if (len < 0) len = strlen (spText);
pdc = dc_HDC2PDC(hdc);
gdi_get_TextOut_extent (pdc, pdc->pLogFont, spText, len, &size);
{
// update text out position
int width = size.cx;
extent_x_SP2LP (pdc, &width);
pdc->CurTextPos.x = x + width;
pdc->CurTextPos.y = y;
}
if (dc_IsGeneralHDC(hdc)) {
pthread_mutex_lock (&pdc->pGCRInfo->lock);
if (!dc_GenerateECRgn (pdc, FALSE)) {
pthread_mutex_unlock (&pdc->pGCRInfo->lock);
return size.cx;
}
}
// Transfer logical to device to screen here.
coor_LP2SP(pdc, &x, &y);
rcOutput.left = x;
rcOutput.top = y;
rcOutput.right = x + size.cx + 1;
rcOutput.bottom = y + size.cy + 1;
NormalizeRect(&rcOutput);
pthread_mutex_lock (&__mg_gdilock);
IntersectRect (&rcOutput, &rcOutput, &pdc->ecrgn.rcBound);
if( !dc_IsMemHDC(hdc) ) ShowCursorForGDI(FALSE, &rcOutput);
// set graphics context.
GAL_SetGC(pdc->gc);
// set text out mode.
pClipRect = pdc->ecrgn.head;
while(pClipRect)
{
if (DoesIntersect (&rcOutput, &pClipRect->rc)) {
GAL_SetClipping(pdc->gc, pClipRect->rc.left, pClipRect->rc.top,
pClipRect->rc.right - 1, pClipRect->rc.bottom - 1);
gdi_strnwrite (pdc, x, y, spText, len);
}
pClipRect = pClipRect->next;
}
if( !dc_IsMemHDC(hdc) ) ShowCursorForGDI(TRUE, &rcOutput);
pthread_mutex_unlock(&__mg_gdilock);
if (dc_IsGeneralHDC(hdc)) pthread_mutex_unlock (&pdc->pGCRInfo->lock);
return size.cx;
}
int GUIAPI TabbedTextOutLen (HDC hdc, int x, int y, const char* spText, int len)
{
PCLIPRECT pClipRect;
PDC pdc;
SIZE size;
RECT rcOutput;
if (len == 0) return 0;
if (len < 0) len = strlen (spText);
pdc = dc_HDC2PDC(hdc);
coor_LP2SP (pdc, &pdc->CurTextPos.x, &pdc->CurTextPos.y);
gdi_get_TabbedTextOut_extent (pdc, pdc->pLogFont, pdc->tabstop, spText, len,
&size, &pdc->CurTextPos);
coor_SP2LP (pdc, &pdc->CurTextPos.x, &pdc->CurTextPos.y);
if (dc_IsGeneralHDC(hdc)) {
pthread_mutex_lock (&pdc->pGCRInfo->lock);
if (!dc_GenerateECRgn (pdc, FALSE)) {
pthread_mutex_unlock (&pdc->pGCRInfo->lock);
return size.cx;
}
}
// Transfer logical to device to screen here.
coor_LP2SP(pdc, &x, &y);
rcOutput.left = x;
rcOutput.top = y;
rcOutput.right = x + size.cx + 1;
rcOutput.bottom = y + size.cy + 1;
NormalizeRect(&rcOutput);
pthread_mutex_lock (&__mg_gdilock);
IntersectRect (&rcOutput, &rcOutput, &pdc->ecrgn.rcBound);
if( !dc_IsMemHDC(hdc) ) ShowCursorForGDI(FALSE, &rcOutput);
// set graphics context.
GAL_SetGC(pdc->gc);
pClipRect = pdc->ecrgn.head;
while(pClipRect)
{
if (DoesIntersect (&rcOutput, &pClipRect->rc)) {
GAL_SetClipping(pdc->gc, pClipRect->rc.left, pClipRect->rc.top,
pClipRect->rc.right - 1, pClipRect->rc.bottom - 1);
gdi_tabbedtextout (pdc, x, y, spText, len);
}
pClipRect = pClipRect->next;
}
if( !dc_IsMemHDC(hdc) ) ShowCursorForGDI(TRUE, &rcOutput);
pthread_mutex_unlock(&__mg_gdilock);
if (dc_IsGeneralHDC(hdc)) pthread_mutex_unlock (&pdc->pGCRInfo->lock);
return size.cx;
}
int GUIAPI TabbedTextOutEx (HDC hdc, int x, int y, const char* spText,
int nCount, int nTabs, int *pTabPos, int nTabOrig)
{
PDC pdc;
int line_len, sub_len;
int nr_tab = 0, tab_pos, def_tab;
int x_orig = x, max_x = x;
int line_height;
int nr_delim_newline, nr_delim_tab;
if (nCount == 0) return 0;
if (nCount < 0) nCount = strlen (spText);
pdc = dc_HDC2PDC(hdc);
line_height = pdc->pLogFont->size + pdc->alExtra + pdc->blExtra;
y += pdc->alExtra;
if (nTabs == 0 || pTabPos == NULL) {
int ave_width = (*pdc->pLogFont->sbc_devfont->font_ops->get_ave_width)
(pdc->pLogFont, pdc->pLogFont->sbc_devfont);
def_tab = ave_width * pdc->tabstop;
}
else
def_tab = pTabPos [nTabs - 1];
while (nCount) {
line_len = substrlen (spText, nCount, '\n', &nr_delim_newline);
nCount -= line_len + nr_delim_newline;
nr_tab = 0;
x = x_orig;
tab_pos = nTabOrig;
while (line_len) {
int i, width;
sub_len = substrlen (spText, line_len, '\t', &nr_delim_tab);
width = TextOutLen (hdc, x, y, spText, sub_len);
x += width;
if (x >= tab_pos) {
while (x >= tab_pos)
tab_pos += (nr_tab >= nTabs) ? def_tab : pTabPos [nr_tab++];
for (i = 0; i < nr_delim_tab - 1; i ++)
tab_pos += (nr_tab >= nTabs) ? def_tab : pTabPos [nr_tab++];
}
else {
for (i = 0; i < nr_delim_tab; i ++)
tab_pos += (nr_tab >= nTabs) ? def_tab : pTabPos [nr_tab++];
}
x = tab_pos;
line_len -= sub_len + nr_delim_tab;
spText += sub_len + nr_delim_tab;
}
if (max_x < x) max_x = x;
spText += nr_delim_newline;
y += line_height * nr_delim_newline;
}
return max_x - x_orig;
}
static void txtDrawOneLine (PDC pdc, const char* pText, int nLen, int x, int y,
const RECT* prcOutput, UINT nFormat, int nTabWidth)
{
RECT rcInter;
PCLIPRECT pClipRect;
pClipRect = pdc->ecrgn.head;
while(pClipRect)
{
if (IntersectRect (&rcInter, prcOutput, &pClipRect->rc)) {
GAL_SetClipping(pdc->gc, rcInter.left, rcInter.top,
rcInter.right - 1, rcInter.bottom - 1);
if (nFormat & DT_EXPANDTABS) {
const char* sub = pText;
const char* left;
int nSubLen = nLen;
int nOutputLen;
while ((left = strnchr (sub, nSubLen, '\t'))) {
nOutputLen = left - sub;
x += gdi_strnwrite (pdc, x, y, sub, nOutputLen);
nSubLen -= (nOutputLen + 1);
sub = left + 1;
x += nTabWidth;
}
if (nSubLen != 0)
gdi_strnwrite (pdc, x, y, sub, nSubLen);
}
else
gdi_strnwrite (pdc, x, y, pText, nLen);
}
pClipRect = pClipRect->next;
}
}
static int txtGetWidthOfNextWord (PDC pdc, const char* pText, int nCount, int* nChars)
{
int width, extra;
DEVFONT* sbc_devfont = pdc->pLogFont->sbc_devfont;
DEVFONT* mbc_devfont = pdc->pLogFont->mbc_devfont;
WORDINFO word_info;
*nChars = 0;
if (nCount == 0) return 0;
extra = pdc->cExtra;
if (mbc_devfont) {
int mbc_pos, sub_len;
mbc_pos = (*mbc_devfont->charset_ops->pos_first_char) (pText, nCount);
if (mbc_pos == 0) {
sub_len = (*mbc_devfont->charset_ops->len_first_substr) (pText, nCount);
(*mbc_devfont->charset_ops->get_next_word) (pText, sub_len, &word_info);
if (pdc->pLogFont->style & FS_WEIGHT_BOLD
&& !(mbc_devfont->style & FS_WEIGHT_BOLD))
extra ++;
width = (*mbc_devfont->font_ops->get_str_width)
(pdc->pLogFont, mbc_devfont, pText, word_info.len, extra);
*nChars = word_info.len;
return width;
}
else if (mbc_pos > 0)
nCount = mbc_pos;
}
(*sbc_devfont->charset_ops->get_next_word) (pText, nCount, &word_info);
if (pdc->pLogFont->style & FS_WEIGHT_BOLD
&& !(sbc_devfont->style & FS_WEIGHT_BOLD))
extra ++;
width = (*sbc_devfont->font_ops->get_str_width)
(pdc->pLogFont, sbc_devfont, pText, word_info.len, extra);
*nChars = word_info.len;
return width;
}
/*
** This function return the normal characters' number (refrence)
** and output width of the line (return value).
*/
static int txtGetOneLine (PDC pdc, const char* pText, int nCount, int nTabWidth,
int maxwidth, UINT uFormat, int* nChar)
{
int x = 0, y = 0;
int wordLen;
int wordWidth;
int lineWidth;
if (uFormat & DT_SINGLELINE) {
SIZE size;
if (uFormat & DT_EXPANDTABS)
gdi_get_TabbedTextOut_extent (pdc, pdc->pLogFont, pdc->tabstop,
pText, nCount, &size, NULL);
else
gdi_get_TextOut_extent (pdc, pdc->pLogFont, pText, nCount, &size);
*nChar = nCount;
return size.cx;
}
*nChar = 0;
lineWidth = 0;
while (TRUE) {
wordWidth = txtGetWidthOfNextWord (pdc, pText, nCount, &wordLen);
if (uFormat & DT_WORDBREAK) {
if (wordWidth > maxwidth) {
SIZE size;
wordLen = GetTextExtentPoint ((HDC)pdc, pText, nCount,
maxwidth - lineWidth, NULL, NULL, NULL, &size);
if (wordLen == 0) {
wordLen = GetFirstMCharLen (GetCurFont ((HDC)pdc), pText, nCount);
gdi_get_TextOut_extent (pdc, pdc->pLogFont, pText, wordLen, &size);
wordWidth = size.cx;
}
*nChar += wordLen;
lineWidth += wordWidth;
break;
}
else if (lineWidth + wordWidth > maxwidth)
break;
}
pText += wordLen;
nCount -= wordLen;
lineWidth += wordWidth;
*nChar += wordLen;
if (nCount == 0)
break;
if (*pText == '\t') {
(*nChar)++;
if (uFormat & DT_EXPANDTABS) {
lineWidth += nTabWidth;
gdi_start_new_line (pdc->pLogFont);
}
else
lineWidth += gdi_width_one_char
(pdc->pLogFont, pdc->pLogFont->sbc_devfont, pText, 1, &x, &y);
pText ++;
nCount --;
}
else if (*pText == '\n' || *pText == '\r') {
(*nChar) ++;
break;
}
else if (*pText == ' ') {
lineWidth += gdi_width_one_char
(pdc->pLogFont, pdc->pLogFont->sbc_devfont, pText, 1, &x, &y);
(*nChar) ++;
pText ++;
nCount --;
}
}
return lineWidth;
}
int DrawTextEx2 (HDC hdc, const char* pText, int nCount,
RECT* pRect, int indent, UINT nFormat, DTFIRSTLINE *firstline)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -