PDA

Click to See Complete Forum and Search --> : Code Layout


CornedBee
Oct 8th, 2002, 11:51 AM
k, the problem is like this:

I develop an MFC application that displays text in small windows that float around the screen. This works fine.
I don't want to use edit controls or rich edit controls for a few reasons.

I now want to parse the text for URLS and make them hyperlinks. Coloring works fine, I just keep track of URL or not while painting.

I also have a function that calculates the size of the output. It basically does the same as the paint function without really painting anything or keeping track of URL or not.

Now the question is, how do I design my code to calculate the POSITION of the link - that is the area where the user can click to get sent there? I could either just store this while painting. Wouldn't be much more code, but gets called more often than necessary.
Or I could add code to calculate that in the function that calculates the size. Would only called when needed, but would require quite a lot more code.

Which do you recommend?

Thx in advance.

jim mcnamara
Oct 8th, 2002, 03:31 PM
What does 'float around the screen' mean?

In constant motion or the user (or the code) repositions them once in a while?

CornedBee
Oct 8th, 2002, 04:18 PM
The user repositions them once in a while. The whole thing is a system for storing information, both hierarchical and by position. So all siblings can be placed at any position on the desktop, while some of those siblings have child items. The user can this way organize his notes, cluster them to groups or whatever.

jim mcnamara
Oct 9th, 2002, 09:48 AM
ok

Assuming the windows do not tile or cascade:

Since the positions seldom change, maintain a linked list of HWNDS & RECTs, text, etc that you can traverse on click. You can resolve the window text (URL).

In general, maintaining your own list of objects that are relatively static is the most reliable method. The lookup becomes faster, with small amounts of code. Updates mean you change the list as you update, which is less prone to failure than trying to do everything at once.

You know the adage - no function should ever have more than 10 lines of operational code.

CornedBee
Oct 9th, 2002, 01:36 PM
Huh?

Look, thanks for your advice, but a) I don't understand what you mean and b) all HWNDs are once stored by windows and then hidden in CWnds which are again stored, this time by MFC in a hash table. I really don't want to store them a third time.

Each window will store a list of RECTs (CRects actually) of the positions of it's links. All I want to know is when the best time to calculate these RECTs. I need to do it at least every time the window gets resized. But it would be less work for me if I did it every time the window gets drawn because most of the code I need for it is already there.

As for the 10-line functions. I know this rule, it's probably good, but I never cared about it and never had any problems. My functions usually are much longer, but comments point out the sections of the function. I found out that I have more trouble finding code when I have many small functions than when I have one large function. Just take a look at my text drawing function!


void CMemoWnd::OnPaint()
{
CPaintDC dc(this);
CRect rect;
GetClientRect(&rect);
CString str;
m_pDoc->GetMemoText(m_id, str);
CFont font;
font.CreatePointFont(110, _T("Times New Roman"), &dc);
CFont fontLink;
fontLink.CreateFont(-MulDiv(11, GetDeviceCaps(dc.GetSafeHdc(), LOGPIXELSY), 72), 0, 0, 0,
FW_NORMAL, 0, 1, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, _T("Times New Roman"));
COLORREF clrNorm = RGB(0,0,0), clrLink = RGB(0,0,255), clrOld = dc.SetTextColor(clrNorm);
CFont *pOldFont = dc.SelectObject(&font);
UINT oldAlign = dc.SetTextAlign(TA_LEFT | TA_TOP | TA_NOUPDATECP);
// offset drawing by the scroll position
int hSc = 0;//m_hBar.GetScrollPos();
int vSc = 0;//m_vBar.GetScrollPos();
// Start the drawing
int x=rect.left-hSc, y=rect.top-vSc;
LPCTSTR szData = str;
LPCTSTR szRunning = NULL;
LPCTSTR szLastWord = szData;
const int sNorm = 0;
const int sURL = 1;
int state = sNorm;
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
int tabWidth = tm.tmAveCharWidth * 4; // Later user ratio
int lineHeight = tm.tmHeight;
for(szRunning = szData; *szRunning; ++szRunning)
{
// Collect characters until either hitting the end of the line or encountering an URL
TCHAR c = *szRunning;
// scan ahead for an URL
if(state == sNorm && _tcsncmp(szRunning, _T("http://"), _tcslen(_T("http://"))) == 0)
{
// output current buffer
CSize size = dc.TabbedTextOut(x, y, szData, szRunning - szData,
1, &tabWidth, rect.left-hSc);
state = sURL;
dc.SelectObject(&fontLink);
dc.SetTextColor(clrLink);
x += size.cx;
szLastWord = szData = szRunning;
continue;
}
if(_istalnum(c))
continue;

if(c == '\r' || c == '\n')
{
CSize size = dc.TabbedTextOut(x, y, szData, szRunning - szData,
1, &tabWidth, rect.left-hSc);
x = 0;
y += lineHeight;
if(c == '\r' && *(szRunning+1) == '\n')
++szRunning;
szData = szLastWord = szRunning+1;
if(state == sURL)
{
state = sNorm;
dc.SetTextColor(clrNorm);
dc.SelectObject(&font);
}
continue;
}

if(c == ' ' || c == '\t')
{
CSize size = dc.GetOutputTabbedTextExtent(szData, szRunning - szData,
1, &tabWidth);
if(size.cx > rect.Width() + hSc)
{
size = dc.TabbedTextOut(x, y, szData, szLastWord - szData,
1, &tabWidth, rect.left-hSc);
x = 0;
y += lineHeight;
szData = szLastWord + 1;
szLastWord = szRunning;
}
if(state == sURL)
{
// output remaining
size = dc.TabbedTextOut(x, y, szData, szRunning - szData,
1, &tabWidth, rect.left-hSc);
dc.SelectObject(&font);
dc.SetTextColor(clrNorm);
x += size.cx;
szLastWord = szRunning;
szData = szRunning;
}
state = sNorm;
}
}

dc.SelectObject(pOldFont);
dc.SetTextAlign(oldAlign);
dc.SetTextColor(clrOld);
}


Of course I could split it into a PrepareDC, a UnprepareDC and a DrawLoop function, but this would give me several problems:
a) Where do I store data that results from PrepareDC and is needed in UnprepareDC or DrawLoop? I could pass several references but this wouldn't increase readability.
b) The main bulk of the function, DrawLoop, should not call any subroutines. Bad enough I need to call the API or CRT functions. The loop gets executed once per character, so I really want to avoid overhead.

All in all I really don't want shorter functions, and I don't care about what Linus Torvald says about formatting code. Though I admit he's probably a far better programmer than me, I still disagree with some of the things he says, especially about Hungarian Notation.

Anyway, thanks that you try to help me.