| author | Raymond Lam | 2011-11-01 01:20:17 (EDT) |
|---|---|---|
| committer | Felipe Heidrich | 2011-11-11 10:51:56 (EST) |
| commit | 4b8def71d48644f2eecf0ad1acd6947c48451ff6 (patch) (side-by-side diff) | |
| tree | 7b7b964b4068e976d02e6e15efe6490a0d0f3a15 | |
| parent | afa64269dcd7778f6eb01e1cb2d17a3455e7a43e (diff) | |
| download | eclipse.platform.swt-4b8def71d48644f2eecf0ad1acd6947c48451ff6.zip eclipse.platform.swt-4b8def71d48644f2eecf0ad1acd6947c48451ff6.tar.gz eclipse.platform.swt-4b8def71d48644f2eecf0ad1acd6947c48451ff6.tar.bz2 | |
Glassify the ToolBar and ToolItem widgets.
3 files changed, 246 insertions, 0 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java index 9cb33cf..4ffc715 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java @@ -1531,6 +1531,14 @@ LRESULT wmNotifyChild (NMHDR hdr, int /*long*/ wParam, int /*long*/ lParam) { // } switch (nmcd.dwDrawStage) { case OS.CDDS_PREERASE: { + if (this.getBufferredPaint()) { + // if buffered painting is on, erase the background the Aero/Glass way + RECT rect = new RECT (); + OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom); + drawBackground (nmcd.hdc, rect); + return new LRESULT (OS.CDRF_SKIPDEFAULT); + } + /* * Bug in Windows. When a tool bar does not have the style * TBSTYLE_FLAT, the rectangle to be erased in CDDS_PREERASE @@ -1546,6 +1554,25 @@ LRESULT wmNotifyChild (NMHDR hdr, int /*long*/ wParam, int /*long*/ lParam) { } return new LRESULT (OS.CDRF_SKIPDEFAULT); } + case OS.CDDS_PREPAINT: { + if (this.getBufferredPaint()) { + // this will trigger the CDDS_ITEMPREPAINT notifications so that we can draw each + // ToolItem individually + return new LRESULT (OS.CDRF_NOTIFYITEMDRAW); + } + break; + } + case OS.CDDS_ITEMPREPAINT: { + if (this.getBufferredPaint()) { + // each ToolItem knows how to draw themself in an Aero/Glass friendly manner + ToolItem childItem = items[nmcd.dwItemSpec]; + if (childItem != null) { + childItem.wmBufferedPaint(this.handle, wParam, lParam); + } + return new LRESULT (OS.CDRF_SKIPDEFAULT); + } + break; + } } break; case OS.TBN_HOTITEMCHANGE: @@ -1590,4 +1617,17 @@ LRESULT wmNotifyChild (NMHDR hdr, int /*long*/ wParam, int /*long*/ lParam) { return super.wmNotifyChild (hdr, wParam, lParam); } +boolean getBufferredPaint() { + Shell shell = getShell (); + if (((shell.style & SWT.TRIM_FILL) != 0) && ((this.style & SWT.TRIM_FILL) != 0)) { + return true; + } + return false; +} + +LRESULT wmBufferedPaint (int /*long*/ hWnd, int /*long*/ wParam, int /*long*/ lParam) { + // toolbar items are owner-draw during buffered painting + return null; +} + } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java index c8caddb..bd965b8 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java @@ -46,6 +46,9 @@ public class ToolItem extends Item { int id; short cx; + // added to support the owner-draw operations performed in an Aero/Glass environment + static final int MARGIN = 4; + /** * Constructs a new instance of this class given its parent * (which must be a <code>ToolBar</code>) and a style value @@ -1018,4 +1021,165 @@ LRESULT wmCommandChild (int /*long*/ wParam, int /*long*/ lParam) { return null; } +/** + * Owner-draw painting of the ToolItem. Used in a shell where Aero/Glass painting has been turned on. + */ +LRESULT wmBufferedPaint (int /*long*/ hWnd, int /*long*/ wParam, int /*long*/ lParam) { + // cast the lParam into a NMCUSTOMDRAW structure + NMCUSTOMDRAW nmcd = new NMCUSTOMDRAW (); + OS.MoveMemory (nmcd, lParam, NMCUSTOMDRAW.sizeof); + int hDC = nmcd.hdc; + RECT rectClient = new RECT (); + OS.SetRect (rectClient, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom); + + // setup the constants that are used during drawing + final boolean drawImage = image != null; + final boolean drawText = text.length () != 0; + final boolean drawTextBelow = (parent.style & SWT.RIGHT) == 0; + final boolean drawDepressed = this.determineButtonState(nmcd) == OS.TS_HOTCHECKED || this.determineButtonState(nmcd) == OS.TS_CHECKED || this.determineButtonState(nmcd) == OS.TS_PRESSED; + final int margin = drawText && drawImage && !drawTextBelow ? MARGIN : 0; + final int width = rectClient.right - rectClient.left; + final int height = rectClient.bottom - rectClient.top; + final TCHAR textBuffer = new TCHAR (parent.getCodePage (), text, true); + + // determine the image width and height + int imageWidth = 0, imageHeight = 0; + if (drawImage) { + Rectangle imageRect = image.getBounds (); + imageWidth = imageRect.width; + imageHeight = imageRect.height; + } + + // determine the text width and height + int textWidth = 0, textHeight = 0, flags = 0; + if (drawText) { + RECT rect2 = new RECT (); + flags = OS.DT_CALCRECT | OS.DT_EDITCONTROL | OS.DT_EXPANDTABS; + if ((style & SWT.LEFT) != 0) flags |= OS.DT_LEFT; + if ((style & SWT.CENTER) != 0) flags |= OS.DT_CENTER; + if ((style & SWT.RIGHT) != 0) flags |= OS.DT_RIGHT; + if ((style & SWT.WRAP) != 0) { + flags |= OS.DT_WORDBREAK; + rect2.right = Math.max (0, width - imageWidth - margin); + } + + OS.DrawText (hDC, textBuffer, -1, rect2, flags); + textWidth = rect2.right - rect2.left; + textHeight = rect2.bottom - rect2.top; + } + + // calculate the image (x,y) coordinate + int x = rectClient.left; + int y = rectClient.top; + if (drawTextBelow) { + x += Math.max (0, (width - imageWidth) / 2); + y += Math.max (0, (height - imageHeight - textHeight) / 2); + } else if ((style & SWT.CENTER) != 0) { + x += Math.max (0, (width - imageWidth - textWidth - margin) / 2); + y += Math.max (0, (height - imageHeight) / 2); + } else if ((style & SWT.RIGHT) != 0) { + x += width - imageWidth - textWidth - margin; + y += Math.max (0, (height - imageHeight) / 2); + } else { + x += margin; + y += Math.max (0, (height - imageHeight) / 2); + } + if (drawDepressed) { + x++; + y--; + } + + // draw the image, if needed + if (drawImage) { + GCData data = new GCData(); + data.device = display; + GC gc = GC.win32_new (hDC, data); + Image image = getEnabled () ? this.image : (this.disabledImage != null) ? this.disabledImage : this.image; + gc.drawImage (image, x, y); + gc.dispose (); + } + + // calculate the text (x,y) coordinate + if (drawTextBelow) { + x = rectClient.left + MARGIN; + y = height - textHeight - MARGIN; + } else { + x += imageWidth + MARGIN; + y = rectClient.top + Math.max (0, (height - textHeight) / 2); + } + if (drawDepressed) { + x++; + y--; + } + + // draw the text, if needed + if (drawText) { + flags &= ~OS.DT_CALCRECT; + rectClient.left = x; + rectClient.right += rectClient.left; + rectClient.top = y; + rectClient.bottom += rectClient.top; + + int color = 0x000000; + int /*long*/ hFont = OS.SendMessage(parent.handle, OS.WM_GETFONT, 0, 0); + this.drawBufferredText(hDC, textBuffer, rectClient, hFont, color, flags); + } + + // draw the outline of the tool item + drawItemOutline(hDC, nmcd); + + return LRESULT.ZERO; +} + +/** + * Draws the outline of the ToolItem. This will make the ToolItem appear as pressed, checked, hot or normal depending + * on the UI state of the toolbar item. + * @param hDC - device context to paint in + * @param nmcd - the NMCUSTOMDRAW structure passed into owner-draw toolbar items + */ +void drawItemOutline(int hDC, NMCUSTOMDRAW nmcd) { + RECT rectClient = new RECT(); + OS.SetRect (rectClient, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom); + + // setup the theme parameters + int /*long*/ hTheme = OS.OpenThemeData(0, "Toolbar;".toCharArray()); + int btnState = determineButtonState(nmcd); + + // draw the button outline, depending on if it's a regular button or a drop-down button + if ((style & SWT.DROP_DOWN) != 0) { + // drop-down button: left half is a button with a right edge that is not rounded + int dropDownWidth = OS.GetSystemMetrics(OS.SM_CXVSCROLL); + rectClient.right -= dropDownWidth; + OS.DrawThemeBackground(hTheme, hDC, OS.TP_SPLITBUTTON, btnState, rectClient, null); + + // drop-down button: right half is where the arrow is drawn + rectClient.left = rectClient.right; + rectClient.right += dropDownWidth; + OS.DrawThemeBackground(hTheme, hDC, OS.TP_SPLITBUTTONDROPDOWN, btnState, rectClient, null); + } else { + // regular button + OS.DrawThemeBackground(hTheme, hDC, OS.TP_BUTTON, btnState, rectClient, null); + } + + OS.CloseThemeData(hTheme); +} + +/** + * Translates the item state into the equivalent button state. + * @param nmcd - the NMCUSTOMDRAW structure passed into owner-draw toolbar items + * @return + */ +int determineButtonState(NMCUSTOMDRAW nmcd) { + int btnState = OS.TS_NORMAL; + + // translate the button state depending on the incoming item state + if ((nmcd.uItemState & OS.CDIS_HOT) != 0 && (nmcd.uItemState & OS.CDIS_CHECKED) != 0) { btnState = OS.TS_HOTCHECKED; } + else if ((nmcd.uItemState & OS.CDIS_HOT) != 0 && (nmcd.uItemState & OS.CDIS_SELECTED) != 0) {btnState = OS.TS_PRESSED; } + else if ((nmcd.uItemState & OS.CDIS_HOT) != 0) { btnState = OS.TS_HOT; } + else if ((nmcd.uItemState & OS.CDIS_SELECTED) != 0) { btnState = OS.TS_PRESSED; } + else if ((nmcd.uItemState & OS.CDIS_CHECKED) != 0) { btnState = OS.TS_CHECKED; } + + return btnState; } + +}
\ No newline at end of file diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java index fb2abeb..f776911 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java @@ -2682,4 +2682,46 @@ LRESULT wmXButtonUp (int /*long*/ hwnd, int /*long*/ wParam, int /*long*/ lParam } return result; } + +public int getThemeGlowSize () { + int /*long*/ hTheme = OS.OpenThemeData(0, "CompositedWindow::Window;".toCharArray()); + int [] glowSize = new int[1]; + OS.GetThemeInt(hTheme, 0, 0, OS.TMT_TEXTGLOWSIZE, glowSize); + OS.CloseThemeData(hTheme); + return glowSize[0] > 0 ? glowSize[0] : 12; +} + +public void drawBufferredText(int targetDC, TCHAR textBuffer, RECT rect, int hFont, int color, int dwFlags) { + // set up the buffered device context - the background is painted entirely black and its alpha + // is set to zero, resulting in a device context that is 100% transparent (if nothing is drawn to this DC, + // the glass background will just render through) + int /*long*/ [] hdcBuffered = new int /*long*/ [1]; + int /*long*/ hBufferedPaint = OS.BeginBufferedPaint(targetDC, rect, OS.BPBF_TOPDOWNDIB, null, hdcBuffered); + OS.PatBlt(hdcBuffered[0], 0, 0, rect.right /* - rect.left */, rect.bottom /* - rect.top */, OS.BLACKNESS); + OS.BufferedPaintSetAlpha(hBufferedPaint, rect, (byte)0x00); + + // setup the DTTOPTS structure for calling into DrawThemeTextEx - note how we call getThemeGlowSize() + // to apply a glow around the text we are drawing to enhance readability of the text against a glass background + DTTOPTS dttOpts = new DTTOPTS(); + dttOpts.dwSize = DTTOPTS.sizeof; + dttOpts.dwFlags = OS.DTT_COMPOSITED | OS.DTT_GLOWSIZE | OS.DTT_TEXTCOLOR; + dttOpts.crText = color; + dttOpts.iGlowSize = getThemeGlowSize (); + + OS.SetTextColor(hdcBuffered[0], color); + if (hFont != 0) { + hFont = OS.SelectObject(hdcBuffered[0], hFont); + } + + // draw the text using the special DrawThemeTextEx call + int /*long*/ hTheme = OS.OpenThemeData(0, "ControlPanelStyle;".toCharArray()); + OS.DrawThemeTextEx(hTheme, hdcBuffered[0], 0, 0, textBuffer.chars, textBuffer.length(), dwFlags, rect, dttOpts); + OS.CloseThemeData(hTheme); + + if (hFont != 0) { + OS.SelectObject(hdcBuffered[0], hFont); + } + OS.EndBufferedPaint(hBufferedPaint, true); + +} } |

