void wxNotebook::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); wxMemoryDC memdc; RECT rc; ::GetClientRect(GetHwnd(), &rc); wxBitmap bmp(rc.right, rc.bottom); memdc.SelectObject(bmp); const wxLayoutDirection dir = dc.GetLayoutDirection(); memdc.SetLayoutDirection(dir); const HDC hdc = GetHdcOf(memdc); // The drawing logic of the native tab control is absolutely impenetrable // but observation shows that in the current Windows versions (XP and 7), // the tab control always erases its entire background in its window proc // when the tabs are top-aligned but does not do it when the tabs are in // any other position. // // This means that we can't rely on our background colour being used for // the blank area in the tab row because this doesn't work in the default // top-aligned case, hence the hack with ExtFloodFill() below. But it also // means that we still do need to erase the DC to account for the other // cases. // // Moreover, just in case some very old or very new (or even future, // although it seems unlikely that this is ever going to change by now) // version of Windows didn't do it like this, do both things in all cases // instead of optimizing away the one of them which doesn't do anything for // the effectively used tab orientation -- better safe than fast. // Notice that we use our own background here, not the background used for // the pages, because the tab row background must blend with the parent and // so the background colour inherited from it (if any) must be used. AutoHBRUSH hbr(wxColourToRGB(GetBackgroundColour())); ::FillRect(hdc, &rc, hbr); MSWDefWindowProc(WM_PAINT, (WPARAM)hdc, 0); // At least for the top-aligned tabs, our background colour was overwritten // and so we now replace the default background with our colour. This is // horribly inefficient, of course, but seems to be the only way to do it. if ( UseBgCol() ) { SelectInHDC selectBrush(hdc, hbr); // Find the point which must contain the default background colour: // this is a hack, of course, but using this point "close" to the // corner seems to work fine in practice. int x = 0, y = 0; switch ( GetWindowStyle() & wxBK_ALIGN_MASK ) { case wxBK_TOP: x = rc.right - 2; y = 2; break; case wxBK_BOTTOM: x = rc.right - 2; y = rc.bottom - 2; break; case wxBK_LEFT: x = 2; y = rc.bottom - 2; break; case wxBK_RIGHT: x = 2; y = rc.bottom - 2; break; } ::ExtFloodFill(hdc, x, y, ::GetSysColor(COLOR_BTNFACE), FLOODFILLSURFACE); } // For some reason in RTL mode, source offset has to be -1, otherwise the // right border (physical) remains unpainted. const wxCoord ofs = dir == wxLayout_RightToLeft ? -1 : 0; dc.Blit(ofs, 0, rc.right, rc.bottom, &memdc, ofs, 0); }
bool wxMenuItem::OnDrawItem(wxDC& dc, const wxRect& rc, wxODAction WXUNUSED(act), wxODStatus stat) { const MenuDrawData* data = MenuDrawData::Get(); wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl(); HDC hdc = GetHdcOf(*impl); RECT rect; wxCopyRectToRECT(rc, rect); int imgWidth = wxMax(GetMarginWidth(), data->CheckSize.cx); if ( IsOwnerDrawn() ) { // font and colors to use wxFont font; GetFontToUse(font); wxColour colText, colBack; GetColourToUse(stat, colText, colBack); // calculate metrics of item parts RECT rcSelection = rect; data->ItemMargin.ApplyTo(rcSelection); RECT rcSeparator = rcSelection; data->SeparatorMargin.ApplyTo(rcSeparator); RECT rcGutter = rcSelection; rcGutter.right = data->ItemMargin.cxLeftWidth + data->CheckBgMargin.cxLeftWidth + data->CheckMargin.cxLeftWidth + imgWidth + data->CheckMargin.cxRightWidth + data->CheckBgMargin.cxRightWidth; RECT rcText = rcSelection; rcText.left = rcGutter.right + data->TextBorder; // we draw the text label vertically centered, but this results in it // being 1px too low compared to native menus for some reason, fix it if ( data->MenuLayout() != MenuDrawData::FullTheme ) rcText.top--; #if wxUSE_UXTHEME // If a custom background colour is explicitly specified, we should use // it instead of the default theme background. wxUxThemeEngine* const theme = GetBackgroundColour().IsOk() ? NULL : MenuDrawData::GetUxThemeEngine(); if ( theme ) { POPUPITEMSTATES state; if ( stat & wxODDisabled ) { state = (stat & wxODSelected) ? MPI_DISABLEDHOT : MPI_DISABLED; } else if ( stat & wxODSelected ) { state = MPI_HOT; } else { state = MPI_NORMAL; } wxUxThemeHandle hTheme(GetMenu()->GetWindow(), L"MENU"); if ( theme->IsThemeBackgroundPartiallyTransparent(hTheme, MENU_POPUPITEM, state) ) { theme->DrawThemeBackground(hTheme, hdc, MENU_POPUPBACKGROUND, 0, &rect, NULL); } theme->DrawThemeBackground(hTheme, hdc, MENU_POPUPGUTTER, 0, &rcGutter, NULL); if ( IsSeparator() ) { rcSeparator.left = rcGutter.right; theme->DrawThemeBackground(hTheme, hdc, MENU_POPUPSEPARATOR, 0, &rcSeparator, NULL); return true; } theme->DrawThemeBackground(hTheme, hdc, MENU_POPUPITEM, state, &rcSelection, NULL); } else #endif // wxUSE_UXTHEME { if ( IsSeparator() ) { DrawEdge(hdc, &rcSeparator, EDGE_ETCHED, BF_TOP); return true; } AutoHBRUSH hbr(colBack.GetPixel()); SelectInHDC selBrush(hdc, hbr); ::FillRect(hdc, &rcSelection, hbr); } // draw text label // using native API because it recognizes '&' HDCTextColChanger changeTextCol(hdc, colText.GetPixel()); HDCBgColChanger changeBgCol(hdc, colBack.GetPixel()); HDCBgModeChanger changeBgMode(hdc, TRANSPARENT); SelectInHDC selFont(hdc, GetHfontOf(font)); // item text name without mnemonic for calculating size wxString text = GetName(); SIZE textSize; ::GetTextExtentPoint32(hdc, text.c_str(), text.length(), &textSize); // item text name with mnemonic text = GetItemLabel().BeforeFirst('\t'); int flags = DST_PREFIXTEXT; // themes menu is using specified color for disabled labels if ( data->MenuLayout() == MenuDrawData::Classic && (stat & wxODDisabled) && !(stat & wxODSelected) ) flags |= DSS_DISABLED; if ( (stat & wxODHidePrefix) && !data->AlwaysShowCues ) flags |= DSS_HIDEPREFIX; int x = rcText.left; int y = rcText.top + (rcText.bottom - rcText.top - textSize.cy) / 2; ::DrawState(hdc, NULL, NULL, wxMSW_CONV_LPARAM(text), text.length(), x, y, 0, 0, flags); // ::SetTextAlign(hdc, TA_RIGHT) doesn't work with DSS_DISABLED or DSS_MONO // as the last parameter in DrawState() (at least with Windows98). So we have // to take care of right alignment ourselves. wxString accel = GetItemLabel().AfterFirst(wxT('\t')); if ( !accel.empty() ) { SIZE accelSize; ::GetTextExtentPoint32(hdc, accel.c_str(), accel.length(), &accelSize); flags = DST_TEXT; // themes menu is using specified color for disabled labels if ( data->MenuLayout() == MenuDrawData::Classic && (stat & wxODDisabled) && !(stat & wxODSelected) ) flags |= DSS_DISABLED; x = rcText.right - data->ArrowMargin.GetTotalX() - data->ArrowSize.cx - data->ArrowBorder; // right align accel on FullTheme menu, left otherwise if ( data->MenuLayout() == MenuDrawData::FullTheme) x -= accelSize.cx; else x -= m_parentMenu->GetMaxAccelWidth(); y = rcText.top + (rcText.bottom - rcText.top - accelSize.cy) / 2; ::DrawState(hdc, NULL, NULL, wxMSW_CONV_LPARAM(accel), accel.length(), x, y, 0, 0, flags); } } // draw the bitmap RECT rcImg; SetRect(&rcImg, rect.left + data->ItemMargin.cxLeftWidth + data->CheckBgMargin.cxLeftWidth + data->CheckMargin.cxLeftWidth, rect.top + data->ItemMargin.cyTopHeight + data->CheckBgMargin.cyTopHeight + data->CheckMargin.cyTopHeight, rect.left + data->ItemMargin.cxLeftWidth + data->CheckBgMargin.cxLeftWidth + data->CheckMargin.cxLeftWidth + imgWidth, rect.bottom - data->ItemMargin.cyBottomHeight - data->CheckBgMargin.cyBottomHeight - data->CheckMargin.cyBottomHeight); if ( IsCheckable() && !m_bmpChecked.IsOk() ) { if ( stat & wxODChecked ) { DrawStdCheckMark((WXHDC)hdc, &rcImg, stat); } } else { wxBitmap bmp; if ( stat & wxODDisabled ) { bmp = GetDisabledBitmap(); } if ( !bmp.IsOk() ) { // for not checkable bitmaps we should always use unchecked one // because their checked bitmap is not set bmp = GetBitmap(!IsCheckable() || (stat & wxODChecked)); #if wxUSE_IMAGE if ( bmp.IsOk() && stat & wxODDisabled ) { // we need to grey out the bitmap as we don't have any specific // disabled bitmap wxImage imgGrey = bmp.ConvertToImage().ConvertToGreyscale(); if ( imgGrey.IsOk() ) bmp = wxBitmap(imgGrey); } #endif // wxUSE_IMAGE } if ( bmp.IsOk() ) { wxMemoryDC dcMem(&dc); dcMem.SelectObjectAsSource(bmp); // center bitmap int nBmpWidth = bmp.GetWidth(), nBmpHeight = bmp.GetHeight(); int x = rcImg.left + (imgWidth - nBmpWidth) / 2; int y = rcImg.top + (rcImg.bottom - rcImg.top - nBmpHeight) / 2; dc.Blit(x, y, nBmpWidth, nBmpHeight, &dcMem, 0, 0, wxCOPY, true); } } return true; }
void wxStaticBox::PaintForeground(wxDC& dc, const RECT& rc) { wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl(); MSWDefWindowProc(WM_PAINT, (WPARAM)GetHdcOf(*impl), 0); // when using XP themes, neither setting the text colour nor transparent // background mode doesn't change anything: the static box def window proc // still draws the label in its own colours, so we need to redraw the text // ourselves if we have a non default fg colour if ( m_hasFgCol && wxUxThemeEngine::GetIfActive() ) { // draw over the text in default colour in our colour HDC hdc = GetHdcOf(*impl); ::SetTextColor(hdc, GetForegroundColour().GetPixel()); const bool rtl = wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft; if ( rtl ) ::SetTextAlign(hdc, TA_RTLREADING | TA_RIGHT); // Get dimensions of the label const wxString label = GetLabel(); // choose the correct font AutoHFONT font; SelectInHDC selFont; if ( m_hasFont ) { selFont.Init(hdc, GetHfontOf(GetFont())); } else // no font set, use the one set by the theme { wxUxThemeHandle hTheme(this, L"BUTTON"); if ( hTheme ) { wxUxThemeFont themeFont; if ( wxUxThemeEngine::Get()->GetThemeFont ( hTheme, hdc, BP_GROUPBOX, GBS_NORMAL, TMT_FONT, themeFont.GetPtr() ) == S_OK ) { font.Init(themeFont.GetLOGFONT()); if ( font ) selFont.Init(hdc, font); } } } // Get the font extent int width, height; dc.GetTextExtent(wxStripMenuCodes(label, wxStrip_Mnemonics), &width, &height); int x; int y = height; // first we need to correctly paint the background of the label // as Windows ignores the brush offset when doing it // // FIXME: value of x is hardcoded as this is what it is on my system, // no idea if it's true everywhere RECT dimensions = {0, 0, 0, y}; if ( !rtl ) { x = 9; dimensions.left = x; dimensions.right = x + width; } else { x = rc.right - 7; dimensions.left = x - width; dimensions.right = x; } // need to adjust the rectangle to cover all the label background dimensions.left -= 2; dimensions.right += 2; dimensions.bottom += 2; if ( UseBgCol() ) { // our own background colour should be used for the background of // the label: this is consistent with the behaviour under pre-XP // systems (i.e. without visual themes) and generally makes sense wxBrush brush = wxBrush(GetBackgroundColour()); wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl(); ::FillRect(GetHdcOf(*impl), &dimensions, GetHbrushOf(brush)); } else // paint parent background { PaintBackground(dc, dimensions); } UINT drawTextFlags = DT_SINGLELINE | DT_VCENTER; // determine the state of UI queues to draw the text correctly under XP // and later systems static const bool isXPorLater = wxGetWinVersion() >= wxWinVersion_XP; if ( isXPorLater ) { if ( ::SendMessage(GetHwnd(), WM_QUERYUISTATE, 0, 0) & UISF_HIDEACCEL ) { drawTextFlags |= DT_HIDEPREFIX; } } // now draw the text if ( !rtl ) { RECT rc2 = { x, 0, x + width, y }; ::DrawText(hdc, label.t_str(), label.length(), &rc2, drawTextFlags); } else // RTL { RECT rc2 = { x, 0, x - width, y }; ::DrawText(hdc, label.t_str(), label.length(), &rc2, drawTextFlags | DT_RTLREADING); } } }
void wxAuiMSWToolBarArt::DrawButton( wxDC& dc, wxWindow* wnd, const wxAuiToolBarItem& item, const wxRect& rect) { if ( m_themed ) { RECT r; wxCopyRectToRECT(rect, r); wxUxThemeHandle hTheme(wnd, L"Toolbar"); wxUxThemeEngine* te = wxUxThemeEngine::Get(); int btnState; if ( item.GetState() & wxAUI_BUTTON_STATE_DISABLED ) btnState = TS_DISABLED; else if ( item.GetState() & wxAUI_BUTTON_STATE_PRESSED ) btnState = TS_PRESSED; else if ( item.GetState() & wxAUI_BUTTON_STATE_HOVER && item.GetState() & wxAUI_BUTTON_STATE_CHECKED ) btnState = TS_HOTCHECKED; else if ( item.GetState() & wxAUI_BUTTON_STATE_CHECKED ) btnState = TS_CHECKED; else if ( item.GetState() & wxAUI_BUTTON_STATE_HOVER ) btnState = TS_HOT; else btnState = TS_NORMAL; te->DrawThemeBackground( hTheme, GetHdcOf(dc.GetTempHDC()), TP_BUTTON, btnState, &r, NULL); int textWidth = 0, textHeight = 0; if ( m_flags & wxAUI_TB_TEXT ) { dc.SetFont(m_font); int tx, ty; dc.GetTextExtent(wxT("ABCDHgj"), &tx, &textHeight); textWidth = 0; dc.GetTextExtent(item.GetLabel(), &textWidth, &ty); } int bmpX = 0, bmpY = 0; int textX = 0, textY = 0; if ( m_textOrientation == wxAUI_TBTOOL_TEXT_BOTTOM ) { bmpX = rect.x + (rect.width / 2) - (item.GetBitmap().GetWidth() / 2); bmpY = rect.y + ((rect.height - textHeight) / 2) - (item.GetBitmap().GetHeight() / 2); textX = rect.x + (rect.width / 2) - (textWidth / 2) + 1; textY = rect.y + rect.height - textHeight - 1; } else if ( m_textOrientation == wxAUI_TBTOOL_TEXT_RIGHT ) { bmpX = rect.x + 3; bmpY = rect.y + (rect.height / 2) - (item.GetBitmap().GetHeight() / 2); textX = bmpX + 3 + item.GetBitmap().GetWidth(); textY = rect.y + (rect.height / 2) - (textHeight / 2); } wxBitmap bmp; if ( item.GetState() & wxAUI_BUTTON_STATE_DISABLED ) bmp = item.GetDisabledBitmap(); else bmp = item.GetBitmap(); if ( bmp.IsOk() ) dc.DrawBitmap(bmp, bmpX, bmpY, true); // set the item's text color based on if it is disabled dc.SetTextForeground(*wxBLACK); if ( item.GetState() & wxAUI_BUTTON_STATE_DISABLED ) dc.SetTextForeground(DISABLED_TEXT_COLOR); if ( (m_flags & wxAUI_TB_TEXT) && !item.GetLabel().empty() ) { dc.DrawText(item.GetLabel(), textX, textY); } } else wxAuiGenericToolBarArt::DrawButton(dc, wnd, item, rect); }
void wxAuiMSWToolBarArt::DrawDropDownButton( wxDC& dc, wxWindow* wnd, const wxAuiToolBarItem& item, const wxRect& rect) { if ( m_themed ) { wxUxThemeHandle hTheme(wnd, L"Toolbar"); wxUxThemeEngine* const te = wxUxThemeEngine::Get(); int dropDownWidth = 14; int textWidth = 0, textHeight = 0, textX = 0, textY = 0; int bmpX = 0, bmpY = 0, dropBmpX = 0, dropBmpY = 0; wxRect buttonRect = wxRect(rect.x, rect.y, rect.width - dropDownWidth, rect.height); wxRect dropDownRect = wxRect(rect.x + rect.width - dropDownWidth - 1, rect.y, dropDownWidth + 1, rect.height); if ( m_flags & wxAUI_TB_TEXT ) { dc.SetFont(m_font); int tx, ty; if ( m_flags & wxAUI_TB_TEXT ) { dc.GetTextExtent(wxT("ABCDHgj"), &tx, &textHeight); textWidth = 0; } dc.GetTextExtent(item.GetLabel(), &textWidth, &ty); } RECT btnR; wxCopyRectToRECT(buttonRect, btnR); RECT dropDownR; wxCopyRectToRECT(dropDownRect, dropDownR); int btnState; if ( item.GetState() & wxAUI_BUTTON_STATE_DISABLED ) btnState = TS_DISABLED; else if ( item.GetState() & wxAUI_BUTTON_STATE_PRESSED ) btnState = TS_PRESSED; else if ( item.GetState() & wxAUI_BUTTON_STATE_HOVER ) btnState = TS_HOT; else btnState = TS_NORMAL; te->DrawThemeBackground( hTheme, GetHdcOf(dc.GetTempHDC()), TP_SPLITBUTTON, btnState, &btnR, NULL); te->DrawThemeBackground( hTheme, GetHdcOf(dc.GetTempHDC()), TP_SPLITBUTTONDROPDOWN, btnState, &dropDownR, NULL); dropBmpX = dropDownRect.x + (dropDownRect.width / 2) - (m_buttonDropDownBmp.GetWidth() / 2); dropBmpY = dropDownRect.y + (dropDownRect.height / 2) - (m_buttonDropDownBmp.GetHeight() / 2); if ( m_textOrientation == wxAUI_TBTOOL_TEXT_BOTTOM ) { bmpX = buttonRect.x + (buttonRect.width / 2) - (item.GetBitmap().GetWidth() / 2); bmpY = buttonRect.y + ((buttonRect.height - textHeight) / 2) - (item.GetBitmap().GetHeight() / 2); textX = rect.x + (rect.width / 2) - (textWidth / 2) + 1; textY = rect.y + rect.height - textHeight - 1; } else if ( m_textOrientation == wxAUI_TBTOOL_TEXT_RIGHT ) { bmpX = rect.x + 3; bmpY = rect.y + (rect.height / 2) - (item.GetBitmap().GetHeight() / 2); textX = bmpX + 3 + item.GetBitmap().GetWidth(); textY = rect.y + (rect.height / 2) - (textHeight / 2); } wxBitmap bmp; if ( item.GetState() & wxAUI_BUTTON_STATE_DISABLED ) { bmp = item.GetDisabledBitmap(); } else { bmp = item.GetBitmap(); } if ( !bmp.IsOk() ) return; dc.DrawBitmap(bmp, bmpX, bmpY, true); // set the item's text color based on if it is disabled dc.SetTextForeground(*wxBLACK); if ( item.GetState() & wxAUI_BUTTON_STATE_DISABLED ) dc.SetTextForeground(DISABLED_TEXT_COLOR); if ( (m_flags & wxAUI_TB_TEXT) && !item.GetLabel().empty() ) { dc.DrawText(item.GetLabel(), textX, textY); } } else wxAuiGenericToolBarArt::DrawDropDownButton(dc, wnd, item, rect); }
void wxComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) ) { // TODO: Convert drawing in this function to Windows API Code wxSize sz = GetClientSize(); wxDC* dcPtr = wxAutoBufferedPaintDCFactory(this); wxDC& dc = *dcPtr; const wxRect& rectButton = m_btnArea; wxRect rectTextField = m_tcArea; // FIXME: Either SetBackgroundColour or GetBackgroundColour // doesn't work under Vista, so here's a temporary // workaround. // In the theme-less rendering code below, this fixes incorrect // background on read-only comboboxes (they are gray, but should be // white). wxColour bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); #if wxUSE_UXTHEME const bool isEnabled = IsThisEnabled(); wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl(); HDC hDc = GetHdcOf(*impl); HWND hWnd = GetHwndOf(this); wxUxThemeHandle hTheme(this, L"COMBOBOX"); #endif // wxUSE_UXTHEME wxRect borderRect(0,0,sz.x,sz.y); if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE ) { borderRect = m_tcArea; borderRect.Inflate(1); } int drawButFlags = 0; #if wxUSE_UXTHEME if ( hTheme ) { const bool useVistaComboBox = ::wxGetWinVersion() >= wxWinVersion_Vista; RECT rFull; wxCopyRectToRECT(borderRect, rFull); RECT rButton; wxCopyRectToRECT(rectButton, rButton); RECT rBorder; wxCopyRectToRECT(borderRect, rBorder); bool isNonStdButton = (m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE) || (m_iFlags & wxCC_IFLAG_HAS_NONSTANDARD_BUTTON); // // Get some states for themed drawing int butState; if ( !isEnabled ) { butState = CBXS_DISABLED; } // Vista will display the drop-button as depressed always // when the popup window is visilbe else if ( (m_btnState & wxCONTROL_PRESSED) || (useVistaComboBox && !IsPopupWindowState(Hidden)) ) { butState = CBXS_PRESSED; } else if ( m_btnState & wxCONTROL_CURRENT ) { butState = CBXS_HOT; } else { butState = CBXS_NORMAL; } int comboBoxPart = 0; // For XP, use the 'default' part RECT* rUseForBg = &rBorder; bool drawFullButton = false; int bgState = butState; const bool isFocused = (FindFocus() == GetMainWindowOfCompositeControl()) ? true : false; if ( useVistaComboBox ) { // Draw the entire control as a single button? if ( !isNonStdButton ) { if ( HasFlag(wxCB_READONLY) ) drawFullButton = true; } if ( drawFullButton ) { comboBoxPart = CP_READONLY; rUseForBg = &rFull; // It should be safe enough to update this flag here. m_iFlags |= wxCC_FULL_BUTTON; } else { comboBoxPart = CP_BORDER; m_iFlags &= ~wxCC_FULL_BUTTON; if ( isFocused ) bgState = CBB_FOCUSED; else bgState = CBB_NORMAL; } } // // Draw parent's background, if necessary RECT* rUseForTb = NULL; if ( ::IsThemeBackgroundPartiallyTransparent( hTheme, comboBoxPart, bgState ) ) rUseForTb = &rFull; else if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE ) rUseForTb = &rButton; if ( rUseForTb ) ::DrawThemeParentBackground( hWnd, hDc, rUseForTb ); // // Draw the control background (including the border) if ( m_widthCustomBorder > 0 ) { ::DrawThemeBackground( hTheme, hDc, comboBoxPart, bgState, rUseForBg, NULL ); } else { // No border. We can't use theme, since it cannot be relied on // to deliver borderless drawing, even with DrawThemeBackgroundEx. dc.SetBrush(bgCol); dc.SetPen(bgCol); dc.DrawRectangle(borderRect); } // // Draw the drop-button if ( !isNonStdButton ) { drawButFlags = Button_BitmapOnly; int butPart = CP_DROPDOWNBUTTON; if ( useVistaComboBox ) { if ( drawFullButton ) { // We need to alter the button style slightly before // drawing the actual button (but it was good above // when background etc was done). if ( butState == CBXS_HOT || butState == CBXS_PRESSED ) butState = CBXS_NORMAL; } if ( m_btnSide == wxRIGHT ) butPart = CP_DROPDOWNBUTTONRIGHT; else butPart = CP_DROPDOWNBUTTONLEFT; } ::DrawThemeBackground( hTheme, hDc, butPart, butState, &rButton, NULL ); } else if ( useVistaComboBox && (m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE) ) { // We'll do this, because DrawThemeParentBackground // doesn't seem to be reliable on Vista. drawButFlags |= Button_PaintBackground; } } else #endif { // Windows 2000 and earlier drawButFlags = Button_PaintBackground; dc.SetBrush(bgCol); dc.SetPen(bgCol); dc.DrawRectangle(borderRect); } // Button rendering (may only do the bitmap on button, depending on the flags) DrawButton( dc, rectButton, drawButFlags ); // Paint required portion of the custom image on the control if ( (!m_text || m_widthCustomPaint) ) { wxASSERT( m_widthCustomPaint >= 0 ); // this is intentionally here to allow drawed rectangle's // right edge to be hidden if ( m_text ) rectTextField.width = m_widthCustomPaint; dc.SetFont( GetFont() ); dc.SetClippingRegion(rectTextField); if ( m_popupInterface ) m_popupInterface->PaintComboControl(dc,rectTextField); else wxComboPopup::DefaultPaintComboControl(this,dc,rectTextField); } delete dcPtr; }
void wxStaticBox::PaintForeground(wxDC& dc, const RECT& rc) { wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl(); MSWDefWindowProc(WM_PAINT, (WPARAM)GetHdcOf(*impl), 0); // when using XP themes, neither setting the text colour nor transparent // background mode doesn't change anything: the static box def window proc // still draws the label in its own colours, so we need to redraw the text // ourselves if we have a non default fg colour if ( m_hasFgCol && wxUxThemeEngine::GetIfActive() ) { // draw over the text in default colour in our colour HDC hdc = GetHdcOf(*impl); ::SetTextColor(hdc, GetForegroundColour().GetPixel()); const bool rtl = wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft; if ( rtl ) ::SetTextAlign(hdc, TA_RTLREADING | TA_RIGHT); // Get dimensions of the label const wxString label = GetLabel(); // choose the correct font AutoHFONT font; SelectInHDC selFont; if ( m_hasFont ) { selFont.Init(hdc, GetHfontOf(GetFont())); } else // no font set, use the one set by the theme { wxUxThemeHandle hTheme(this, L"BUTTON"); if ( hTheme ) { // GetThemeFont() expects its parameter to be LOGFONTW and not // LOGFONTA even in ANSI programs and will happily corrupt // memory after the struct end if we pass a LOGFONTA (which is // smaller) to it! LOGFONTW lfw; if ( wxUxThemeEngine::Get()->GetThemeFont ( hTheme, hdc, BP_GROUPBOX, GBS_NORMAL, TMT_FONT, (LOGFONT *)&lfw ) == S_OK ) { #if wxUSE_UNICODE // ok, no conversion necessary const LOGFONT& lf = lfw; #else // !wxUSE_UNICODE // most of the fields are the same in LOGFONTA and LOGFONTW LOGFONT lf; memcpy(&lf, &lfw, sizeof(lf)); // but the face name must be converted WideCharToMultiByte(CP_ACP, 0, lfw.lfFaceName, -1, lf.lfFaceName, sizeof(lf.lfFaceName), NULL, NULL); #endif // wxUSE_UNICODE/!wxUSE_UNICODE font.Init(lf); if ( font ) selFont.Init(hdc, font); } } } // Get the font extent int width, height; dc.GetTextExtent(wxStripMenuCodes(label, wxStrip_Mnemonics), &width, &height); int x; int y = height; // first we need to correctly paint the background of the label // as Windows ignores the brush offset when doing it // // FIXME: value of x is hardcoded as this is what it is on my system, // no idea if it's true everywhere RECT dimensions = {0, 0, 0, y}; if ( !rtl ) { x = 9; dimensions.left = x; dimensions.right = x + width; } else { x = rc.right - 7; dimensions.left = x - width; dimensions.right = x; } // need to adjust the rectangle to cover all the label background dimensions.left -= 2; dimensions.right += 2; dimensions.bottom += 2; if ( UseBgCol() ) { // our own background colour should be used for the background of // the label: this is consistent with the behaviour under pre-XP // systems (i.e. without visual themes) and generally makes sense wxBrush brush = wxBrush(GetBackgroundColour()); wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl(); ::FillRect(GetHdcOf(*impl), &dimensions, GetHbrushOf(brush)); } else // paint parent background { PaintBackground(dc, dimensions); } // now draw the text if ( !rtl ) { RECT rc2 = { x, 0, x + width, y }; ::DrawText(hdc, label.wx_str(), label.length(), &rc2, DT_SINGLELINE | DT_VCENTER); } else // RTL { RECT rc2 = { x, 0, x - width, y }; ::DrawText(hdc, label.wx_str(), label.length(), &rc2, DT_SINGLELINE | DT_VCENTER | DT_RTLREADING); } } }
void wxWindowsPrintPreview::DetermineScaling() { ScreenHDC dc; int logPPIScreenX = ::GetDeviceCaps(dc, LOGPIXELSX); int logPPIScreenY = ::GetDeviceCaps(dc, LOGPIXELSY); m_previewPrintout->SetPPIScreen(logPPIScreenX, logPPIScreenY); // Get a device context for the currently selected printer wxPrinterDC printerDC(m_printDialogData.GetPrintData()); int printerWidthMM; int printerHeightMM; int printerXRes; int printerYRes; int logPPIPrinterX; int logPPIPrinterY; wxRect paperRect; if ( printerDC.IsOk() ) { wxPrinterDCImpl *impl = (wxPrinterDCImpl*) printerDC.GetImpl(); HDC hdc = GetHdcOf(*impl); printerWidthMM = ::GetDeviceCaps(hdc, HORZSIZE); printerHeightMM = ::GetDeviceCaps(hdc, VERTSIZE); printerXRes = ::GetDeviceCaps(hdc, HORZRES); printerYRes = ::GetDeviceCaps(hdc, VERTRES); logPPIPrinterX = ::GetDeviceCaps(hdc, LOGPIXELSX); logPPIPrinterY = ::GetDeviceCaps(hdc, LOGPIXELSY); paperRect = printerDC.GetPaperRect(); if ( logPPIPrinterX == 0 || logPPIPrinterY == 0 || printerWidthMM == 0 || printerHeightMM == 0 ) { m_isOk = false; } } else { // use some defaults printerWidthMM = 150; printerHeightMM = 250; printerXRes = 1500; printerYRes = 2500; logPPIPrinterX = 600; logPPIPrinterY = 600; paperRect = wxRect(0, 0, printerXRes, printerYRes); m_isOk = false; } m_pageWidth = printerXRes; m_pageHeight = printerYRes; m_previewPrintout->SetPageSizePixels(printerXRes, printerYRes); m_previewPrintout->SetPageSizeMM(printerWidthMM, printerHeightMM); m_previewPrintout->SetPaperRectPixels(paperRect); m_previewPrintout->SetPPIPrinter(logPPIPrinterX, logPPIPrinterY); // At 100%, the page should look about page-size on the screen. m_previewScaleX = float(logPPIScreenX) / logPPIPrinterX; m_previewScaleY = float(logPPIScreenY) / logPPIPrinterY; }
bool wxWindowsPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt) { sm_abortIt = false; sm_abortWindow = NULL; if (!printout) { sm_lastError = wxPRINTER_ERROR; return false; } if (m_printDialogData.GetMinPage() < 1) m_printDialogData.SetMinPage(1); if (m_printDialogData.GetMaxPage() < 1) m_printDialogData.SetMaxPage(9999); // Create a suitable device context wxPrinterDC *dc wxDUMMY_INITIALIZE(NULL); if (prompt) { dc = wxDynamicCast(PrintDialog(parent), wxPrinterDC); if (!dc) return false; } else { dc = new wxPrinterDC(m_printDialogData.GetPrintData()); } // May have pressed cancel. if (!dc || !dc->IsOk()) { if (dc) delete dc; return false; } wxPrinterDCImpl *impl = (wxPrinterDCImpl*) dc->GetImpl(); HDC hdc = ::GetDC(NULL); int logPPIScreenX = ::GetDeviceCaps(hdc, LOGPIXELSX); int logPPIScreenY = ::GetDeviceCaps(hdc, LOGPIXELSY); ::ReleaseDC(NULL, hdc); int logPPIPrinterX = ::GetDeviceCaps((HDC) impl->GetHDC(), LOGPIXELSX); int logPPIPrinterY = ::GetDeviceCaps((HDC) impl->GetHDC(), LOGPIXELSY); if (logPPIPrinterX == 0 || logPPIPrinterY == 0) { delete dc; sm_lastError = wxPRINTER_ERROR; return false; } printout->SetPPIScreen(logPPIScreenX, logPPIScreenY); printout->SetPPIPrinter(logPPIPrinterX, logPPIPrinterY); // Set printout parameters printout->SetDC(dc); int w, h; dc->GetSize(&w, &h); printout->SetPageSizePixels((int)w, (int)h); printout->SetPaperRectPixels(dc->GetPaperRect()); dc->GetSizeMM(&w, &h); printout->SetPageSizeMM((int)w, (int)h); // Create an abort window wxBusyCursor busyCursor; printout->OnPreparePrinting(); // Get some parameters from the printout, if defined int fromPage, toPage; int minPage, maxPage; printout->GetPageInfo(&minPage, &maxPage, &fromPage, &toPage); if (maxPage == 0) { sm_lastError = wxPRINTER_ERROR; return false; } // Only set min and max, because from and to have been // set by the user m_printDialogData.SetMinPage(minPage); m_printDialogData.SetMaxPage(maxPage); wxPrintAbortDialog *win = CreateAbortWindow(parent, printout); wxYield(); ::SetAbortProc(GetHdcOf(*impl), wxAbortProc); if (!win) { wxLogDebug(wxT("Could not create an abort dialog.")); sm_lastError = wxPRINTER_ERROR; delete dc; return false; } sm_abortWindow = win; sm_abortWindow->Show(); wxSafeYield(); printout->OnBeginPrinting(); sm_lastError = wxPRINTER_NO_ERROR; int minPageNum = minPage, maxPageNum = maxPage; if ( !m_printDialogData.GetAllPages() ) { minPageNum = m_printDialogData.GetFromPage(); maxPageNum = m_printDialogData.GetToPage(); } // The dc we get from the PrintDialog will do multiple copies without help // if the device supports it. Loop only if we have created a dc from our // own m_printDialogData or the device does not support multiple copies. // m_printDialogData.GetPrintData().GetNoCopies() is set from device // devMode in printdlg.cpp/wxWindowsPrintDialog::ConvertFromNative() const int maxCopyCount = !prompt || !m_printDialogData.GetPrintData().GetNoCopies() ? m_printDialogData.GetNoCopies() : 1; for ( int copyCount = 1; copyCount <= maxCopyCount; copyCount++ ) { if ( !printout->OnBeginDocument(minPageNum, maxPageNum) ) { wxLogError(_("Could not start printing.")); sm_lastError = wxPRINTER_ERROR; break; } if (sm_abortIt) { sm_lastError = wxPRINTER_CANCELLED; break; } int pn; for ( pn = minPageNum; pn <= maxPageNum && printout->HasPage(pn); pn++ ) { win->SetProgress(pn - minPageNum + 1, maxPageNum - minPageNum + 1, copyCount, maxCopyCount); if ( sm_abortIt ) { sm_lastError = wxPRINTER_CANCELLED; break; } dc->StartPage(); bool cont = printout->OnPrintPage(pn); dc->EndPage(); if ( !cont ) { sm_lastError = wxPRINTER_CANCELLED; break; } } printout->OnEndDocument(); } printout->OnEndPrinting(); if (sm_abortWindow) { sm_abortWindow->Show(false); wxDELETE(sm_abortWindow); } delete dc; return sm_lastError == wxPRINTER_NO_ERROR; }
// draw the item bool wxOwnerDrawn::OnDrawItem(wxDC& dc, const wxRect& rc, wxODAction, wxODStatus stat) { // we do nothing if item isn't ownerdrawn if ( !IsOwnerDrawn() ) return true; wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl(); HDC hdc = GetHdcOf(*impl); RECT rect; wxCopyRectToRECT(rc, rect); { // set the font and colors wxFont font; GetFontToUse(font); wxColour colText, colBack; GetColourToUse(stat, colText, colBack); SelectInHDC selFont(hdc, GetHfontOf(font)); wxMSWImpl::wxTextColoursChanger textCol(hdc, colText, colBack); wxMSWImpl::wxBkModeChanger bkMode(hdc, wxBRUSHSTYLE_TRANSPARENT); AutoHBRUSH hbr(wxColourToPalRGB(colBack)); SelectInHDC selBrush(hdc, hbr); ::FillRect(hdc, &rect, hbr); // using native API because it recognizes '&' wxString text = GetName(); SIZE sizeRect; ::GetTextExtentPoint32(hdc, text.c_str(), text.length(), &sizeRect); int flags = DST_PREFIXTEXT; if ( (stat & wxODDisabled) && !(stat & wxODSelected) ) flags |= DSS_DISABLED; if ( (stat & wxODHidePrefix) ) flags |= DSS_HIDEPREFIX; int x = rc.x + GetMarginWidth(); int y = rc.y + (rc.GetHeight() - sizeRect.cy) / 2; int cx = rc.GetWidth() - GetMarginWidth(); int cy = sizeRect.cy; ::DrawState(hdc, NULL, NULL, wxMSW_CONV_LPARAM(text), text.length(), x, y, cx, cy, flags); } // reset to default the font, colors and brush if (stat & wxODHasFocus) ::DrawFocusRect(hdc, &rect); return true; }
bool wxPrinterDCImpl::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, wxDC *source, wxCoord WXUNUSED(xsrc), wxCoord WXUNUSED(ysrc), wxRasterOperationMode WXUNUSED(rop), bool useMask, wxCoord WXUNUSED(xsrcMask), wxCoord WXUNUSED(ysrcMask)) { wxDCImpl *impl = source->GetImpl(); wxMSWDCImpl *msw_impl = wxDynamicCast(impl, wxMSWDCImpl); if (!msw_impl) return false; wxBitmap& bmp = msw_impl->GetSelectedBitmap(); wxMask *mask = useMask ? bmp.GetMask() : NULL; if ( mask ) { // If we are printing source colours are screen colours not printer // colours and so we need copy the bitmap pixel by pixel. RECT rect; HDC dcSrc = GetHdcOf(*msw_impl); MemoryHDC dcMask(dcSrc); SelectInHDC selectMask(dcMask, (HBITMAP)mask->GetMaskBitmap()); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { COLORREF cref = ::GetPixel(dcMask, x, y); if (cref) { HBRUSH brush = ::CreateSolidBrush(::GetPixel(dcSrc, x, y)); rect.left = xdest + x; rect.right = rect.left + 1; rect.top = ydest + y; rect.bottom = rect.top + 1; ::FillRect(GetHdc(), &rect, brush); ::DeleteObject(brush); } } } } else // no mask { if ( !(::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB) || !DrawBitmapUsingStretchDIBits(GetHdc(), bmp, xdest, ydest) ) { // no support for StretchDIBits // as we are printing, source colours are screen colours not // printer colours and so we need copy the bitmap pixel by pixel. HDC dcSrc = GetHdcOf(*msw_impl); RECT rect; for (int y = 0; y < height; y++) { // optimization: draw identical adjacent pixels together. for (int x = 0; x < width; x++) { COLORREF col = ::GetPixel(dcSrc, x, y); HBRUSH brush = ::CreateSolidBrush( col ); rect.left = xdest + x; rect.top = ydest + y; while( (x + 1 < width) && (::GetPixel(dcSrc, x + 1, y) == col ) ) { ++x; } rect.right = xdest + x + 1; rect.bottom = rect.top + 1; ::FillRect((HDC) m_hDC, &rect, brush); ::DeleteObject(brush); } } } } return true; }
void wxAuiMSWTabArt::DrawButton(wxDC& dc, wxWindow* wnd, const wxRect& in_rect, int bitmap_id, int button_state, int orientation, wxRect* out_rect) { if ( !IsThemed() ) { wxAuiGenericTabArt::DrawButton(dc, wnd, in_rect, bitmap_id, button_state, orientation, out_rect); return; } const wchar_t* themeId = NULL; int part = 0; switch (bitmap_id) { case wxAUI_BUTTON_CLOSE: themeId = L"Window"; part = WP_CLOSEBUTTON; break; case wxAUI_BUTTON_LEFT: themeId = L"Spin"; part = SPNP_DOWNHORZ; break; case wxAUI_BUTTON_RIGHT: themeId = L"Spin"; part = SPNP_UPHORZ; break; case wxAUI_BUTTON_WINDOWLIST: themeId = L"Combobox"; part = CP_DROPDOWNBUTTON; break; } wxRect rect = in_rect; if ( orientation == wxLEFT ) { rect.SetX(in_rect.x); rect.SetY(((in_rect.y + in_rect.height) / 2) - (m_closeBtnSize.GetHeight() / 2)); rect.SetWidth(m_closeBtnSize.GetWidth()); rect.SetHeight(m_closeBtnSize.GetHeight()); } else { rect = wxRect(in_rect.x + in_rect.width - m_closeBtnSize.GetWidth(), ((in_rect.y + in_rect.height) / 2) - (m_closeBtnSize.GetHeight() / 2), m_closeBtnSize.GetWidth(), m_closeBtnSize.GetHeight()); } if ( bitmap_id == wxAUI_BUTTON_LEFT || bitmap_id == wxAUI_BUTTON_RIGHT ) { rect.y = in_rect.y; rect.height = in_rect.height - wnd->FromDIP(7); } dc.SetPen(*wxTRANSPARENT_PEN); dc.SetBrush(wxBrush(m_baseColour)); dc.DrawRectangle(rect); int btnState; if ( button_state == wxAUI_BUTTON_STATE_DISABLED ) btnState = TTCS_PRESSED + 1; else if ( button_state == wxAUI_BUTTON_STATE_HOVER ) btnState = TTCS_HOT; else if ( button_state == wxAUI_BUTTON_STATE_PRESSED ) btnState = TTCS_PRESSED; else btnState = TTCS_NORMAL; wxUxThemeHandle hTheme(wnd, themeId); wxRect btnRect(rect); btnRect.width -= wnd->FromDIP(1); RECT btnR; wxCopyRectToRECT(btnRect, btnR); ::DrawThemeBackground(hTheme, GetHdcOf(dc.GetTempHDC()), part, btnState, &btnR, NULL); if ( out_rect ) *out_rect = rect; }
void wxAuiMSWTabArt::DrawTab(wxDC& dc, wxWindow* wnd, const wxAuiNotebookPage& page, const wxRect& in_rect, int close_button_state, wxRect* out_tab_rect, wxRect* out_button_rect, int* x_extent) { if ( !IsThemed() ) { wxAuiGenericTabArt::DrawTab(dc, wnd, page, in_rect, close_button_state, out_tab_rect, out_button_rect, x_extent); return; } if ( !m_closeBtnSize.IsFullySpecified() ) InitSizes(wnd, dc); // figure out the size of the tab wxSize tabSize = GetTabSize(dc, wnd, page.caption, page.bitmap, page.active, close_button_state, x_extent); wxCoord tabHeight = tabSize.y; wxCoord tabWidth = tabSize.x; wxCoord tabX = in_rect.x; wxCoord tabY = 0; if (!page.active) { tabY += wnd->FromDIP(2); tabHeight -= wnd->FromDIP(2); } else { tabX -= wnd->FromDIP(2); tabWidth += wnd->FromDIP(4); tabHeight += 2; } int clipWidth = tabWidth; if ( tabX + clipWidth > in_rect.x + in_rect.width ) clipWidth = (in_rect.x + in_rect.width) - tabX; dc.SetClippingRegion(tabX - wnd->FromDIP(2), tabY, clipWidth + wnd->FromDIP(4), tabHeight); // draw tab wxRect tabRect(tabX, tabY, tabWidth, tabHeight); int tabState; if ( page.active ) tabState = TIS_SELECTED; else if ( page.hover ) tabState = TIS_HOT; else tabState = TIS_NORMAL; wxUxThemeHandle hTabTheme(wnd, L"Tab"); RECT tabR; wxCopyRectToRECT(tabRect, tabR); ::DrawThemeBackground(hTabTheme, GetHdcOf(dc.GetTempHDC()), TABP_TABITEM, tabState, &tabR, NULL); // Apparently, in at least some Windows 10 installations the call above // does not draw the left edge of the first tab and it needs to be drawn // separately, or it wouldn't be drawn at all. if ( tabX == GetIndentSize() ) { ::DrawThemeBackground ( hTabTheme, GetHdcOf(dc.GetTempHDC()), TABP_TABITEMLEFTEDGE, tabState, &tabR, NULL ); } wxRect textRect = tabRect; if ( !page.active ) textRect.Offset(0, wnd->FromDIP(1)); if ( close_button_state != wxAUI_BUTTON_STATE_HIDDEN ) textRect.width -= m_closeBtnSize.x + wnd->FromDIP(3); dc.SetFont(wnd->GetFont()); dc.DrawLabel(page.caption, page.bitmap, textRect, wxALIGN_CENTRE); // draw focus rectangle if ( page.active && (wnd->FindFocus() == wnd) ) { wxRect focusRect = tabRect; focusRect.Deflate(wnd->FromDIP(2)); wxRendererNative::Get().DrawFocusRect(wnd, dc, focusRect, 0); } // draw close button if ( close_button_state != wxAUI_BUTTON_STATE_HIDDEN ) { wxUxThemeHandle hToolTipTheme(wnd, L"TOOLTIP"); int btnState; if ( close_button_state == wxAUI_BUTTON_STATE_HOVER ) btnState = TTCS_HOT; else if ( close_button_state == wxAUI_BUTTON_STATE_PRESSED ) btnState = TTCS_PRESSED; else btnState = TTCS_NORMAL; int offsetY = tabY; if ( wxGetWinVersion() < wxWinVersion_Vista ) offsetY++; // WinXP theme needs a little more padding wxRect rect(tabX + tabWidth - m_closeBtnSize.x - wnd->FromDIP(4), offsetY + (tabHeight / 2) - (m_closeBtnSize.y / 2), m_closeBtnSize.x, m_closeBtnSize.y); RECT btnR; wxCopyRectToRECT(rect, btnR); ::DrawThemeBackground(hToolTipTheme, GetHdcOf(dc.GetTempHDC()), TTP_CLOSE, btnState, &btnR, NULL); if ( out_button_rect ) *out_button_rect = rect; } *out_tab_rect = wxRect(tabX, tabY, tabWidth, tabHeight); dc.DestroyClippingRegion(); }
void GutterCtrl::DrawGutter(wxDC& dc) { Lines& lines = m_editorCtrl.m_lines; const wxSize size = GetClientSize(); m_mdc.Clear(); const unsigned int bg_xpos = m_gutterLeft ? size.x-1 : 0; const unsigned int edge_xpos = m_gutterLeft ? size.x-2 : 1; // Draw the edge m_mdc.SetPen(m_theme.backgroundColor); m_mdc.DrawLine(bg_xpos, 0, bg_xpos, size.y); m_mdc.SetPen(m_edgecolor); m_mdc.DrawLine(edge_xpos, 0, edge_xpos, size.y); // Draw the line numbers m_mdc.SetTextForeground(m_numbercolor); wxString number; const int scrollPos = m_editorCtrl.scrollPos; const unsigned int firstline = lines.GetLineFromYPos(scrollPos); const unsigned int linecount = lines.GetLineCount(); // Prepare for foldings const vector<cxFold>& folds = m_editorCtrl.GetFolds(); vector<cxFold>::const_iterator nextFold = folds.begin(); const unsigned int line_middle = lines.GetLineHeight() / 2; vector<const cxFold*> foldStack; if (m_showFolds) { m_editorCtrl.UpdateFolds(); #ifdef __WXDEBUG__ bool debug = false; if (debug) { for (vector<cxFold>::const_iterator f = folds.begin(); f != folds.end(); ++f) { const wxString indent(wxT('.'), f->indent); wxLogDebug(wxT("%d: %s%d"), f->line_id, indent.c_str(), f->type); } } #endif for (nextFold = folds.begin(); nextFold != folds.end() && nextFold->line_id < firstline; ++nextFold) { if (nextFold->type != cxFOLD_END) { foldStack.push_back(&*nextFold); continue; } // check if end marker matches any starter on the stack for (vector<const cxFold*>::reverse_iterator p = foldStack.rbegin(); p != foldStack.rend(); ++p) { if ((*p)->indent != nextFold->indent) continue; foldStack.erase(p.base()-1, foldStack.end()); // pop break; } } } // Prepare for bookmarks const vector<cxBookmark>& bookmarks = m_editorCtrl.GetBookmarks(); vector<cxBookmark>::const_iterator nextBookmark = bookmarks.begin(); while(nextBookmark != bookmarks.end() && nextBookmark->line_id < firstline) ++nextBookmark; // Draw each line for (unsigned int i = firstline; i < linecount; ++i) { number.Printf(wxT("%*u"), m_max_digits, i+1); const int ypos = lines.GetYPosFromLine(i) - scrollPos; if (ypos > size.y) break; // Highlight selections if (m_currentSel != -1 && ((i >= m_sel_startline && i <= m_sel_endline) || (i >= m_sel_endline && i <= m_sel_startline))) { const int ypos2 = lines.GetBottomYPosFromLine(i) - scrollPos; m_mdc.SetPen(m_hlightcolor); m_mdc.SetBrush(wxBrush(m_hlightcolor, wxSOLID)); m_mdc.DrawRectangle(0, ypos, size.x-2, ypos2-ypos); } // Draw bookmark if (m_showBookmarks && nextBookmark != bookmarks.end() && nextBookmark->line_id == i) { //m_mdc.DrawText(wxT("\u066D"), 3, ypos); m_mdc.DrawBitmap(m_bmBookmark, 2, ypos + line_middle - 5); ++nextBookmark; } // Draw the line number m_mdc.DrawText(number, m_numberX, ypos); // Draw fold markers if (m_showFolds) { bool drawFoldLine = (!foldStack.empty()); if (nextFold != folds.end() && nextFold->line_id == i) { if (nextFold->type == cxFOLD_START) { const int ypos2 = lines.GetBottomYPosFromLine(i) - scrollPos; const unsigned int box_y = ypos + line_middle - 5; m_mdc.DrawBitmap(m_bmFoldOpen, m_foldStartX, box_y); if (&*nextFold == m_currentFold) m_mdc.SetPen(wxPen(m_edgecolor, 2)); else m_mdc.SetPen(m_edgecolor); m_mdc.DrawLine(m_foldStartX+4, box_y+9, m_foldStartX+4, ypos2); foldStack.push_back(&*nextFold); drawFoldLine = false; ++nextFold; } else if (nextFold->type == cxFOLD_START_FOLDED) { const unsigned int box_y = ypos + line_middle - 5; m_mdc.DrawBitmap(m_bmFoldClosed, m_foldStartX, box_y); drawFoldLine = false; // Advance to end of fold i += nextFold->count; while (nextFold != folds.end() && nextFold->line_id <= i) ++nextFold; } else if (nextFold->type == cxFOLD_END) { if (!foldStack.empty()) { // check if end marker matches any starter on the stack (ignore unmatched) for (vector<const cxFold*>::reverse_iterator f = foldStack.rbegin(); f != foldStack.rend(); ++f) { if (nextFold->indent == (*f)->indent) { vector<const cxFold*>::iterator fb = (++f).base(); // Check if we should highlight fold line if (*fb == m_currentFold) m_mdc.SetPen(wxPen(m_edgecolor, 2)); else m_mdc.SetPen(m_edgecolor); // If we are closing other folds, we want to leave a gap const unsigned int ytop = (fb < foldStack.end()-1) ? ypos + 2 : ypos; // Draw end marker const unsigned int middle_y = ypos + line_middle+1; m_mdc.DrawLine(m_foldStartX+4, ytop, m_foldStartX+4, middle_y); m_mdc.DrawLine(m_foldStartX+4, middle_y, m_foldStartX+9, middle_y); foldStack.erase(fb, foldStack.end()); // pop drawFoldLine = false; break; } } } ++nextFold; } } if (drawFoldLine) { const int ypos2 = lines.GetBottomYPosFromLine(i) - scrollPos; // Check if we should highlight fold line if (!foldStack.empty() && foldStack.back() == m_currentFold) { m_mdc.SetPen(wxPen(m_edgecolor, 2)); } else m_mdc.SetPen(m_edgecolor); m_mdc.DrawLine(m_foldStartX+4, ypos, m_foldStartX+4, ypos2); } } } // Copy MemoryDC to Display #ifdef __WXMSW__ ::BitBlt(GetHdcOf(dc), 0, 0,(int)size.x, (int)size.y, GetHdcOf(m_mdc), 0, 0, SRCCOPY); #else dc.Blit(0, 0, size.x, size.y, &m_mdc, 0, 0); #endif }