void SkeinWindow::StartEdit(Skein::Node* node, bool label) { std::map<Skein::Node*,CRect>::const_iterator it = m_nodes.find(node); if (it != m_nodes.end()) { CDibSection* back = m_bitmaps[BackUnplayed]; CRect nodeRect = it->second; if (label) { nodeRect.InflateRect((node->GetLabelTextWidth()-nodeRect.Width())/2,0); nodeRect.InflateRect(m_fontSize.cx,0); nodeRect.top += (back->GetSize().cy/2); nodeRect.top -= (int)(0.12*m_fontSize.cy); nodeRect.top -= (int)(2.1*m_fontSize.cy); nodeRect.bottom = nodeRect.top + m_fontSize.cy+1; m_edit.SetFont(&m_labelFont); } else { nodeRect.DeflateRect(m_fontSize.cx*3,0); nodeRect.top += (back->GetSize().cy/2); nodeRect.top -= (int)(0.12*m_fontSize.cy); nodeRect.top -= (int)(0.5*m_fontSize.cy); nodeRect.bottom = nodeRect.top + m_fontSize.cy+1; m_edit.SetFont(theApp.GetFont(InformApp::FontDisplay)); } m_edit.StartEdit(node,nodeRect,label); } }
void SkeinWindow::DrawLinePixel(CDC& dc, CDibSection& bitmap, int x, int y, double i, COLORREF fore) { CSize size = bitmap.GetSize(); if ((x < 0) || (y < 0) || (x >= size.cx) || (y >= size.cy)) return; COLORREF back = bitmap.GetPixelColour(x,y); int r = (int)(((1.0-i)*GetRValue(fore))+(i*GetRValue(back))); int g = (int)(((1.0-i)*GetGValue(fore))+(i*GetGValue(back))); int b = (int)(((1.0-i)*GetBValue(fore))+(i*GetBValue(back))); bitmap.SetPixel(x,y,(r<<16)|(g<<8)|b); }
CDibSection* FlatButton::GetImage(const char* name, const CSize& size, bool light) { // Is the image in the cache? CString scaleName; scaleName.Format("%s-scaled",name); if (light) scaleName += "-light"; CDibSection* dib = theApp.GetCachedImage(scaleName); if (dib != NULL) return dib; // Create the scaled image CDibSection* original_dib = theApp.GetCachedImage(name); CSize original_size = original_dib->GetSize(); double scaleX = (double)size.cx / (double)original_size.cx; double scaleY = (double)size.cy / (double)original_size.cy; dib = theApp.CreateScaledImage(original_dib,scaleX,scaleY); if (light) { int sr, sg, sb, a; DWORD src; CSize size = dib->GetSize(); for (int y = 0; y < size.cy; y++) { for (int x = 0; x < size.cx; x++) { src = dib->GetPixel(x,y); sb = src & 0xFF; src >>= 8; sg = src & 0xFF; src >>= 8; sr = src & 0xFF; src >>= 8; a = src & 0xFF; const double lighten = 0.4; sr = (int)(0xFF - ((0xFF - sr) * lighten)); sg = (int)(0xFF - ((0xFF - sg) * lighten)); sb = (int)(0xFF - ((0xFF - sb) * lighten)); dib->SetPixel(x,y,(a<<24)|(sr<<16)|(sg<<8)|sb); } } } theApp.CacheImage(scaleName,dib); return dib; }
CDibSection* InformApp::CreateScaledImage(CDibSection* fromImage, double scaleX, double scaleY) { // Work out the scaled image size CSize fromSize = fromImage->GetSize(); CSize newSize((int)(fromSize.cx*scaleX),(int)(fromSize.cy*scaleY)); // Create a scaled image CDibSection* newImage = new CDibSection(); CDC* dc = AfxGetMainWnd()->GetDC(); BOOL created = newImage->CreateBitmap(dc->GetSafeHdc(),newSize.cx,newSize.cy); ASSERT(created); AfxGetMainWnd()->ReleaseDC(dc); // Scale and stretch the image ScaleGfx(fromImage->GetBits(),fromSize.cx,fromSize.cy, newImage->GetBits(),newSize.cx,newSize.cy); return newImage; }
CDibSection* SkeinWindow::GetImage(const char* name, bool dark, bool blend) { // Is the image in the cache? CString skeinName; skeinName.Format("%s-%s",name,dark ? "scaled-dark" : "scaled"); CDibSection* dib = theApp.GetCachedImage(skeinName); if (dib != NULL) return dib; // Create the scaled image dib = theApp.CreateScaledImage(theApp.GetCachedImage(name), m_fontSize.cx*(1.4/7.0),m_fontSize.cy*(1.4/17.0)); // Darken and alpha blend with the background colour if (dark) dib->Darken(0.7); if (blend) dib->AlphaBlend(theApp.GetColour(InformApp::ColourBack)); theApp.CacheImage(skeinName,dib); return dib; }
CRect SourceWindow::PaintEdge(CDC& dcPaint, int y, int w, CDibSection* image, bool top) { // Create a bitmap to draw into CDC dc; dc.CreateCompatibleDC(&dcPaint); CDibSection bitmap; CSize sz = image->GetSize(); if (bitmap.CreateBitmap(dc.GetSafeHdc(),w,sz.cy) == FALSE) return CRect(0,0,0,0); bitmap.FillSolid(::GetSysColor(COLOR_BTNFACE)); // Draw the torn edge int x = 0; while (x < w) { bitmap.AlphaBlend(image,x,0); x += sz.cx; } // Draw the arrow button CDibSection* btn = theApp.GetCachedImage("TearArrow"); CRect btnRect(CPoint(w/2,sz.cy/2),CSize(0,0)); CSize btnSize(btn->GetSize()); btnRect.InflateRect(btnSize.cx/2,btnSize.cy/2); bitmap.AlphaBlend(btn,btnRect.left,btnRect.top,!top); // Copy the bitmap to the device context CBitmap* oldBitmap = CDibSection::SelectDibSection(dc,&bitmap); dcPaint.BitBlt(0,y,w,sz.cy,&dc,0,0,SRCCOPY); dc.SelectObject(oldBitmap); // Return a rectangle around the arrow button btnRect.InflateRect(btnSize.cx/2,btnSize.cy/2); btnRect.OffsetRect(0,y); return btnRect; }
CDibSection* SourceWindow::CreateTornImage(const char* inputImage, const char* outputName) { CDibSection* input = theApp.GetCachedImage(inputImage); CSize inputSize = input->GetSize(); CDibSection* output = new CDibSection(); CDC* dc = AfxGetMainWnd()->GetDC(); BOOL created = output->CreateBitmap(dc->GetSafeHdc(),inputSize.cx,inputSize.cy); ASSERT(created); AfxGetMainWnd()->ReleaseDC(dc); int br = GetRValue(m_back); int bg = GetGValue(m_back); int bb = GetBValue(m_back); int r, g, b, a; DWORD src; for (int y = 0; y < inputSize.cy; y++) { for (int x = 0; x < inputSize.cx; x++) { src = input->GetPixel(x,y); b = src & 0xFF; src >>= 8; g = src & 0xFF; src >>= 8; r = src & 0xFF; src >>= 8; a = src & 0xFF; r = (r * br) >> 8; g = (g * bg) >> 8; b = (b * bb) >> 8; output->SetPixel(x,y,(a<<24)|(r<<16)|(g<<8)|b); } } theApp.CacheImage(outputName,output); return output; }
CDibSection::CDibSection(const CDibSection &dib) : hBitmap(0), Bits(0) { if (Create(dib.Width(), dib.Height(), dib.Depth())) Copy(dib); }
CDibSection* InformApp::GetImage(const char* path) { // Check if it's a PNG file CStdioFile imageFile; if (!imageFile.Open(path,CFile::modeRead|CFile::typeBinary)) return 0; png_byte fileHeader[8]; imageFile.Read(fileHeader,8); bool isPNG = (png_sig_cmp(fileHeader,0,8) == 0); if (isPNG) { // Prepare to read the PNG file png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,(png_voidp)NULL,NULL,NULL); if (png_ptr == NULL) return 0; png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr,(png_infopp)NULL,(png_infopp)NULL); return 0; } png_infop end_info = png_create_info_struct(png_ptr); if (end_info == NULL) { png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)NULL); return 0; } // Set up the point to return to in case of error png_bytep* rowPointers = NULL; if (setjmp(png_jmpbuf(png_ptr))) { if (rowPointers) delete[] rowPointers; png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); return 0; } png_init_io(png_ptr,imageFile.m_pStream); png_set_sig_bytes(png_ptr,8); png_read_info(png_ptr,info_ptr); // Get details of the image png_uint_32 width = png_get_image_width(png_ptr,info_ptr); png_uint_32 height = png_get_image_height(png_ptr,info_ptr); int bit_depth = png_get_bit_depth(png_ptr,info_ptr); int color_type = png_get_color_type(png_ptr,info_ptr); // Set up transforms to the required format if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) png_set_palette_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); if (png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); double gamma; if (png_get_gAMA(png_ptr,info_ptr,&gamma)) png_set_gamma(png_ptr,2.2,gamma); if (bit_depth == 16) png_set_strip_16(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); png_set_bgr(png_ptr); png_set_filler(png_ptr,0xFF,PNG_FILLER_AFTER); // Create a bitmap HDC dc = ::GetDC(NULL); CDibSection* dib = new CDibSection(); BOOL created = dib->CreateBitmap(dc,width,height); ::ReleaseDC(NULL,dc); if (!created) { png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); return NULL; } // Read in the image rowPointers = new png_bytep[height]; for (int i = 0; i < (int)height; i++) rowPointers[i] = ((png_bytep)dib->GetBits())+(width*i*4); png_read_image(png_ptr,rowPointers); png_read_end(png_ptr,end_info); delete[] rowPointers; png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); return dib; } else { imageFile.SeekToBegin(); struct jpeg_decompress_struct info; struct JPEGErrorInfo error; // Initialize the error handling info.err = jpeg_std_error(&(error.base)); error.base.error_exit = errorJPEGExit; error.base.output_message = outputJPEGMessage; if (setjmp(error.errorJump)) { jpeg_destroy_decompress(&info); return NULL; } // Set up the decompression jpeg_create_decompress(&info); jpeg_stdio_src(&info,imageFile.m_pStream); // Read the image attributes jpeg_read_header(&info,TRUE); jpeg_calc_output_dimensions(&info); int width = info.output_width; int height = info.output_height; // Force RGB output info.out_color_space = JCS_RGB; // Create a bitmap HDC dc = ::GetDC(NULL); CDibSection* dib = new CDibSection(); BOOL created = dib->CreateBitmap(dc,width,height); ::ReleaseDC(NULL,dc); if (!created) { jpeg_destroy_decompress(&info); return NULL; } // Get an output buffer JSAMPARRAY buffer = (*info.mem->alloc_sarray) ((j_common_ptr)&info,JPOOL_IMAGE,width*3,1); // Read in the image jpeg_start_decompress(&info); while ((int)info.output_scanline < height) { jpeg_read_scanlines(&info,buffer,1); BYTE* pixelRow = ((BYTE*)dib->GetBits())+(width*(info.output_scanline-1)*4); for (int i = 0; i < width; i++) { pixelRow[(i*4)+0] = (*buffer)[(i*3)+2]; pixelRow[(i*4)+1] = (*buffer)[(i*3)+1]; pixelRow[(i*4)+2] = (*buffer)[(i*3)+0]; pixelRow[(i*4)+3] = 0xFF; } } jpeg_finish_decompress(&info); jpeg_destroy_decompress(&info); return dib; } }
void FlatButton::DrawItem(LPDRAWITEMSTRUCT dis) { CDC* dcPaint = CDC::FromHandle(dis->hDC); CRect rectPaint(dis->rcItem); bool disabled = (dis->itemState & ODS_DISABLED) != 0; // Create a bitmap to paint into CDC dc; dc.CreateCompatibleDC(dcPaint); CRect rect(0,0,rectPaint.Width(),rectPaint.Height()); CDibSection bitmap; if (bitmap.CreateBitmap(dc.GetSafeHdc(),rect.Width(),rect.Height()) == FALSE) return; CBitmap* oldBitmap = CDibSection::SelectDibSection(dc,&bitmap); // Draw the background if (dis->itemState & ODS_SELECTED) { // Get the bitmap to indicate a selected button CBitmap selectBitmap; selectBitmap.LoadBitmap(IDR_FLAT_SELECT); CDC selectDC; selectDC.CreateCompatibleDC(&dc); CBitmap* oldBitmap = selectDC.SelectObject(&selectBitmap); // Get the bitmap's dimensions BITMAP bitmapInfo; selectBitmap.GetBitmap(&bitmapInfo); // Stretch the bitmap into the selected item's background dc.StretchBlt(0,0,rect.Width(),rect.Height(), &selectDC,0,0,bitmapInfo.bmWidth,bitmapInfo.bmHeight,SRCCOPY); selectDC.SelectObject(oldBitmap); } else dc.FillSolidRect(rect,::GetSysColor(COLOR_BTNFACE)); // Get the button's text CString text; GetWindowText(text); // Draw the contents of the button if (text == "?<") { CRect imageRect(rect); if (imageRect.Width() > imageRect.Height()) imageRect.DeflateRect((imageRect.Width() - imageRect.Height())/2,0); int gap = imageRect.Height()/6; imageRect.DeflateRect(gap,gap); CDibSection* dib = GetImage("Arrow-left",imageRect.Size(),disabled); bitmap.AlphaBlend(dib,gap,gap,FALSE); } else if (text == "?>") { CRect imageRect(rect); if (imageRect.Width() > imageRect.Height()) imageRect.DeflateRect((imageRect.Width() - imageRect.Height())/2,0); int gap = imageRect.Height()/6; imageRect.DeflateRect(gap,gap); CDibSection* dib = GetImage("Arrow-right",imageRect.Size(),disabled); bitmap.AlphaBlend(dib,gap,gap,FALSE); } // Draw the separator CPen shadowPen(PS_SOLID,0,::GetSysColor(COLOR_BTNSHADOW)); dc.SelectObject(shadowPen); int gap = rect.Height()/6; dc.MoveTo(rect.right-1,gap); dc.LineTo(rect.right-1,rect.bottom-gap); // Draw the control from the bitmap dcPaint->BitBlt(rectPaint.left,rectPaint.top,rectPaint.Width(),rectPaint.Height(),&dc,0,0,SRCCOPY); dc.SelectObject(oldBitmap); }
void TranscriptWindow::OnDraw(CDC* pDC) { CRect clientRect; GetClientRect(clientRect); CDC dc; dc.CreateCompatibleDC(pDC); // Create an off-screen bitmap for drawing CDibSection bitmap; if (bitmap.CreateBitmap(pDC->GetSafeHdc(),clientRect.Width(),clientRect.Height()) == FALSE) return; CBitmap* oldBitmap = CDibSection::SelectDibSection(dc,&bitmap); dc.SetBkMode(TRANSPARENT); dc.FillSolidRect(clientRect,theApp.GetColour(InformApp::ColourBack)); if (m_skein->IsActive()) { CFont* oldFont = dc.SelectObject(theApp.GetFont(InformApp::FontDisplay)); CPen linePen(PS_SOLID,1,theApp.GetColour(InformApp::ColourBorder)); CPen* oldPen = dc.SelectObject(&linePen); int y = 0; int yinput = m_layout.fontSize.cy+(2*m_layout.margin.cy); // If the transcript is taller than the window, work out the drawing origin if (GetHeight() > clientRect.Height()) { SCROLLINFO scroll; ::ZeroMemory(&scroll,sizeof scroll); scroll.cbSize = sizeof scroll; GetScrollInfo(SB_VERT,&scroll); y -= scroll.nPos; } // Clear the map of visible buttons and expected texts m_buttons.clear(); m_expecteds.clear(); // Loop over the transcript nodes std::deque<NodeLayout>::const_iterator nodeIt; for (nodeIt = m_layout.nodes.begin(); nodeIt != m_layout.nodes.end(); ++nodeIt) { const NodeLayout& nl = *nodeIt; // Is this node visible? CRect nodeRect(0,y,1,y+m_layout.fontSize.cy+nl.height+(4*m_layout.margin.cy)+1); CRect intersection; if (intersection.IntersectRect(nodeRect,clientRect) == FALSE) { // Not visible, so increase the y position and try the next node y += yinput+nl.height+(2*m_layout.margin.cy); continue; } // Get the text associated with the node const CStringW& transcript = nl.node->GetTranscriptText(); const CStringW& expected = nl.node->GetExpectedText(); const CStringW& line = nl.node->GetLine(); // Fill in the background of the input line dc.FillSolidRect(0,y+1,clientRect.Width(),yinput, theApp.GetColour(InformApp::ColourTransInput)); // Fill in the background of the transcript text COLORREF back; if (transcript.IsEmpty()) back = theApp.GetColour(InformApp::ColourTransUnset); else { back = theApp.GetColour(nl.node->GetChanged() ? InformApp::ColourTransDiffers : InformApp::ColourTransSame); } CRect backRect(0,y+yinput,m_layout.columnWidth, y+m_layout.fontSize.cy+nl.height+(4*m_layout.margin.cy)); dc.FillSolidRect(backRect,back); // Fill in the background of the expected text if (expected.IsEmpty()) back = theApp.GetColour(InformApp::ColourTransUnset); else { switch (nl.node->GetDiffers()) { case Skein::Node::ExpectedSame: back = theApp.GetColour(InformApp::ColourTransSame); break; case Skein::Node::ExpectedNearlySame: back = RGB(255,255,127); break; case Skein::Node::ExpectedDifferent: back = theApp.GetColour(InformApp::ColourTransDiffers); break; default: ASSERT(FALSE); back = theApp.GetColour(InformApp::ColourTransDiffers); break; } } backRect.OffsetRect(m_layout.columnWidth+1,0); dc.FillSolidRect(backRect,Brighter(back)); // If this is the first node in the transcript, draw a horizontal line at the top if (nl.node == m_skein->GetRoot()) { dc.MoveTo(0,y); dc.LineTo(clientRect.Width(),y); } // Draw a horizontal line below the node's input dc.MoveTo(0,y+yinput); dc.LineTo(clientRect.Width(),y+yinput); // Draw a final horizontal line below the text boxes dc.MoveTo(0,y+yinput+nl.height+(2*m_layout.margin.cy)); dc.LineTo(clientRect.Width(),y+yinput+nl.height+(2*m_layout.margin.cy)); // Draw a dividing line between the two text boxes dc.MoveTo(m_layout.columnWidth,y+yinput); dc.LineTo(m_layout.columnWidth,y+yinput+nl.height+(2*m_layout.margin.cy)); // If this is the last played knot in the skein, draw a yellow border around it if (nl.node == m_skeinPlayed) { CRect backRect(0,y,clientRect.Width(), y+m_layout.fontSize.cy+nl.height+(4*m_layout.margin.cy)); DrawInsideRect(dc,backRect,CSize(m_layout.margin.cx*3/4,m_layout.margin.cy*7/8), theApp.GetColour(InformApp::ColourTransPlayed)); } // If this is the knot selected in the skein, draw a blue border around it if (nl.node == m_skeinSelected) { CRect backRect(0,y,clientRect.Width(), y+m_layout.fontSize.cy+nl.height+(4*m_layout.margin.cy)); DrawInsideRect(dc,backRect,CSize(m_layout.margin.cx*3/8,m_layout.margin.cy*7/16), theApp.GetColour(InformApp::ColourTransSelect)); } // Draw the buttons at the end of the input line, and store their positions int btnHeight = m_layout.fontSize.cy+m_layout.margin.cy; CRect btnRect( CPoint(clientRect.Width()-(m_layout.margin.cy/2),y+(m_layout.margin.cy/2)), CSize(0,btnHeight)); btnRect = DrawButton(dc,btnRect,false,"Show knot",Button(nl.node,ButtonShow),true); btnRect.right = btnRect.left-(m_layout.margin.cy/2); DrawButton(dc,btnRect,false,"Play to here",Button(nl.node,ButtonPlay),true); // Write the node's input dc.SetTextColor(theApp.GetColour(InformApp::ColourText)); CRect textRect(m_layout.margin.cx,y+m_layout.margin.cy, btnRect.left-m_layout.margin.cx,y+yinput); theOS.DrawText(&dc,line,line.GetLength(),textRect,DT_SINGLELINE|DT_NOPREFIX|DT_END_ELLIPSIS); // Draw the 'bless' button, and store its position y += yinput; btnRect.right = m_layout.columnWidth; btnRect.top = y+(((nl.height+(2*m_layout.margin.cy))-btnHeight)/2); btnRect.bottom = btnRect.top+btnHeight; DrawButton(dc,btnRect,true,"Bless",Button(nl.node,ButtonBless),nl.node->CanBless()); // Write the text in the text boxes textRect = CRect(m_layout.margin.cx,y+m_layout.margin.cy, m_layout.columnWidth-m_layout.centreMargin,y+m_layout.margin.cy+nl.height); DrawText(dc,textRect,transcript,nl.node->GetTranscriptDiffs()); textRect.OffsetRect(m_layout.columnWidth+m_layout.centreMargin-m_layout.margin.cx,0); DrawText(dc,textRect,expected,nl.node->GetExpectedDiffs()); textRect.InflateRect(theApp.MeasureFont(m_edit.GetFont()).cx/4,0); m_expecteds.push_back(std::make_pair(backRect,Expected(nl.node,textRect))); // Advance the y position y += nl.height+(2*m_layout.margin.cy); } dc.SelectObject(oldPen); dc.SelectObject(oldFont); // If the edit window is visible, exclude the area under it to reduce flicker if (m_edit.IsWindowVisible()) { CRect editRect; m_edit.GetWindowRect(&editRect); ScreenToClient(&editRect); pDC->ExcludeClipRect(editRect); } } // Copy to the on-screen device context pDC->BitBlt(0,0,clientRect.Width(),clientRect.Height(),&dc,0,0,SRCCOPY); dc.SelectObject(oldBitmap); }
void SkeinWindow::DrawNodeBack(Skein::Node* node, CDC& dc, CDibSection& bitmap, const CPoint& centre, int width, CDibSection* back) { // Create a device context for the source bitmap CDC dcFrom; dcFrom.CreateCompatibleDC(&dc); CBitmap* fromBitmap = CDibSection::SelectDibSection(dcFrom,back); int y = centre.y-(back->GetSize().cy/2)+(int)(0.12*m_fontSize.cy); int edgeWidth = m_fontSize.cx*4; // Draw the rounded edges of the background dc.BitBlt(centre.x-(width/2)-edgeWidth,y,edgeWidth,back->GetSize().cy, &dcFrom,0,0,SRCCOPY); dc.BitBlt(centre.x+(width/2),y,edgeWidth,back->GetSize().cy, &dcFrom,back->GetSize().cx-edgeWidth,0,SRCCOPY); // Draw the rest of the background { int x = centre.x-(width/2); while (x < centre.x+(width/2)) { int w = back->GetSize().cx-(2*edgeWidth); ASSERT(w > 0); if (x+w > centre.x+(width/2)) w = centre.x+(width/2)-x; dc.BitBlt(x,y,w,back->GetSize().cy,&dcFrom,edgeWidth,0,SRCCOPY); x += w; } } // Draw the "differs badge", if needed if ((node->GetDiffers() != Skein::Node::ExpectedSame) && (node->GetExpectedText().IsEmpty() == FALSE)) { CDibSection* badge = m_bitmaps[DiffersBadge]; CSize badgeSize = badge->GetSize(); bitmap.AlphaBlend(badge, centre.x+(width/2)+edgeWidth-badgeSize.cx,y+back->GetSize().cy-badgeSize.cy); } // Draw the label background, if needed if (ShowLabel(node)) { CDibSection::SelectDibSection(dcFrom,m_bitmaps[BackAnnotate]); int labelWidth = node->GetLabelTextWidth(); int labelHeight = (int)(0.9*back->GetSize().cy); int labelY = y - (int)(1.8*m_fontSize.cy); dc.BitBlt(centre.x-(labelWidth/2)-edgeWidth,labelY,edgeWidth,labelHeight, &dcFrom,0,0,SRCCOPY); dc.BitBlt(centre.x+(labelWidth/2),labelY,edgeWidth,labelHeight, &dcFrom,back->GetSize().cx-edgeWidth,0,SRCCOPY); int x = centre.x-(labelWidth/2); while (x < centre.x+(labelWidth/2)) { int w = back->GetSize().cx-(2*edgeWidth); if (x+w > centre.x+(labelWidth/2)) w = centre.x+(labelWidth/2)-x; dc.BitBlt(x,labelY,w,labelHeight,&dcFrom,edgeWidth,0,SRCCOPY); x += w; } } dcFrom.SelectObject(fromBitmap); // Store the node's size and position m_nodes[node] = CRect( CPoint(centre.x-(width/2)-edgeWidth,y), CSize(width+(2*edgeWidth),back->GetSize().cy)); }
void SkeinWindow::OnDraw(CDC* pDC) { // Clear out any previous node positions m_nodes.clear(); // Get the dimensions of the window CRect client; GetClientRect(client); // Create a memory device context CDC dc; dc.CreateCompatibleDC(pDC); // Create a memory bitmap CDibSection bitmap; if (bitmap.CreateBitmap(pDC->GetSafeHdc(),client.Width(),client.Height()) == FALSE) return; CBitmap* oldBitmap = CDibSection::SelectDibSection(dc,&bitmap); CFont* oldFont = dc.SelectObject(theApp.GetFont(InformApp::FontDisplay)); CPoint origin = pDC->GetViewportOrg(); // Clear the background dc.FillSolidRect(client,theApp.GetColour(InformApp::ColourBack)); if (m_skein->IsActive()) { // Redo the layout if needed m_skein->Layout(dc,&m_labelFont,m_fontSize.cx*10,false); // Work out the position of the centre of the root node CPoint rootCentre(origin); rootCentre.y += (int)(m_fontSize.cy*2.2); // If there is no horizontal scrollbar, centre the root node BOOL horiz, vert; CheckScrollBars(horiz,vert); if (horiz) rootCentre.x += GetTotalSize().cx/2; else rootCentre.x += client.Width()/2; // Get the end node of the transcript Skein::Node* transcriptEnd = (Skein::Node*) GetParentFrame()->SendMessage(WM_TRANSCRIPTEND); // Draw all nodes DrawNodeTree(m_skein->GetRoot(),transcriptEnd,dc,bitmap,client, CPoint(0,0),rootCentre,m_fontSize.cy*5); // If the edit window is visible, exclude the area under it to reduce flicker if (m_edit.IsWindowVisible()) { CRect editRect; m_edit.GetWindowRect(&editRect); ScreenToClient(&editRect); editRect -= pDC->GetViewportOrg(); pDC->ExcludeClipRect(editRect); } } // Draw the memory bitmap on the window's device context pDC->BitBlt(-origin.x,-origin.y,client.Width(),client.Height(),&dc,0,0,SRCCOPY); // Restore the original device context settings dc.SelectObject(oldFont); dc.SelectObject(oldBitmap); }