2 #define WIN32_LEAN_AND_MEAN
11 bool gui::drivers::XGetBorderWidths(Window window, Box box);
19 #define CORNER (BORDER * 2)
24 #define BUTTON_OFFSET 2
26 #define NAME_OFFSETX 4
32 #define GRADIENT_SMOOTHNESS 1.0f
34 #define TEXT_COLOR black
37 #define GRADIENT_DIRECTION horizontal
39 static ColorKey gradient[] =
41 { Color { 128, 128, 255}, 0.00f },
42 { Color { 254, 254, 254}, 0.60f },
43 { Color { 0, 0, 255}, 1.00f }
47 #define GRADIENT_DIRECTION vertical
48 static ColorKey gradient[] =
50 //{ ColorAlpha { 255, { 180, 200, 220} }, 0.00f },
51 { ColorAlpha { 255, menuBarColor }, 0.00f },
52 { ColorAlpha { 255, { 255, 255, 255} }, 0.60f },
53 { ColorAlpha { 255, { 158, 158, 160} }, 1.00f }
56 static ColorKey gradientInactive[] =
58 //{ ColorAlpha { 255, { 160, 180, 200} }, 0.00f },
59 { ColorAlpha { 255, popupMenuColor }, 0.00f },
60 { ColorAlpha { 255, { 220, 220, 220} }, 0.60f },
61 { ColorAlpha { 255, { 120, 120, 120} }, 1.00f }
65 #define GRADIENT_DIRECTION horizontal
66 #define TEXT_COLOR white
68 //#define TEXT_INACTIVE Color { 212,208,200 }
69 #define TEXT_INACTIVE Color { 40, 50, 60 }
71 static ColorKey gradient[] =
73 { ColorAlpha { 255, Color { 10, 36, 106 } }, 0.00f },
74 { ColorAlpha { 255, Color { 166, 202, 240 } }, 1.00f }
76 static ColorKey gradientInactive[] =
78 { ColorAlpha { 255, Color { 128, 128, 128 } }, 0.00f },
79 { ColorAlpha { 255, Color { 192, 192, 192 } }, 1.00f }
82 char * cursorsBitmaps[] =
84 "<:ecere>cursors/arrow.png",
85 "<:ecere>cursors/iBeam.png",
86 "<:ecere>cursors/cross.png",
87 "<:ecere>cursors/move.png",
88 "<:ecere>cursors/sizeNorthEastSouthWest.png",
89 "<:ecere>cursors/sizeNorthSouth.png",
90 "<:ecere>cursors/sizeNorthWestSouthEast.png",
91 "<:ecere>cursors/sizeWestEast.png",
92 "<:ecere>cursors/move.png"
95 static Point cursorsHotSpots[] =
107 static char * skinBitmaps[SkinBitmap] =
109 "<:ecere>elements/areaMinimize.png",
110 "<:ecere>elements/areaMaximize.png",
111 "<:ecere>elements/areaRestore.png",
112 "<:ecere>elements/areaClose.png"
115 class WindowsSkin : Skin
117 class_property(name) = "Windows";
118 class_property(selectionColor) = Color { 10, 36, 106 };
119 class_property(selectionText) = (Color)white;
120 class_property(disabledFrontColor) = Color { 128,128,128 };
121 class_property(disabledBackColor) = (Color)white;
123 FontResource ::SystemFont()
125 return FontResource { faceName = $"Tahoma", size = 8.25f };
128 FontResource ::CaptionFont()
130 return FontResource { faceName = $"Tahoma", size = 8.25f, bold = true };
133 char * ::CursorsBitmaps(uint id, int * hotSpotX, int *hotSpotY, byte ** paletteShades)
135 *hotSpotX = cursorsHotSpots[id].x;
136 *hotSpotY = cursorsHotSpots[id].y;
137 *paletteShades = null;
138 return cursorsBitmaps[id];
141 BitmapResource ::GetBitmap(SkinBitmap id)
143 return BitmapResource { fileName = skinBitmaps[id] };
146 int ::VerticalSBW() { return SB_WIDTH; }
147 int ::HorizontalSBH() { return SB_HEIGHT; }
151 public class WindowsSkin_Window : Window
153 void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h)
157 if(hasMenuBar && state != minimized)
159 *h += skinMenuHeight;
161 if(statusBar && state != minimized)
163 *h += statusBarHeight;
166 if(nativeDecorations && rootWindow == this && windowHandle)
169 RECT rcClient = { 0 }, rcWindow = { 0 };
170 if(GetClientRect(windowHandle, &rcClient) && GetWindowRect(windowHandle, &rcWindow))
172 *w += (rcWindow.right - rcWindow.left) - rcClient.right;
173 *h += (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
176 // PrintLn(_class.name, " is at l = ", rcWindow.left, ", r = ", rcWindow.right);
179 XGetBorderWidths(this, widths);
180 *w += widths.left + widths.right;
181 *h += widths.top + widths.bottom;
185 if((((BorderBits)borderStyle).deep || ((BorderBits)borderStyle).bevel) && state != minimized)
190 if(((BorderBits)borderStyle).sizable && (state == normal))
195 if(((BorderBits)borderStyle).fixed && (state != maximized || !GetParentMenuBar()))
198 if(!((BorderBits)borderStyle).sizable || state == minimized)
204 if(((BorderBits)borderStyle).contour && !((BorderBits)borderStyle).fixed)
211 void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh)
213 bool isNormal = (state == normal);
214 if(nativeDecorations && rootWindow == this && windowHandle) return;
215 if(((BorderBits)borderStyle).fixed && (state != maximized || !GetParentMenuBar()))
222 if(((BorderBits)borderStyle).sizable && isNormal)
224 // GetDecorationsSize(window, mw, mh);
230 if(hasVertScroll && hasHorzScroll)
232 *mw += 2 * SB_WIDTH + SB_WIDTH;
233 *mh += 2 * SB_HEIGHT + SB_HEIGHT;
234 if(((BorderBits)borderStyle).sizable && isNormal)
239 void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch)
241 bool isNormal = (state == normal);
242 MinMaxValue aw = 0, ah = 0;
248 *y += skinMenuHeight;
251 GetDecorationsSize(&aw, &ah);
253 if(nativeDecorations && rootWindow == this && windowHandle)
257 POINT client00 = { 0, 0 };
258 ClientToScreen(windowHandle, &client00);
259 GetWindowRect(windowHandle, &rcWindow);
260 *x += client00.x - rcWindow.left;
261 *y += client00.y - rcWindow.top;
264 XGetBorderWidths(this, widths);
271 // Compute client area start
272 if(((BorderBits)borderStyle).deep || ((BorderBits)borderStyle).bevel)
278 if(((BorderBits)borderStyle).sizable && isNormal)
284 if(((BorderBits)borderStyle).fixed && (state != maximized || !GetParentMenuBar()))
287 if(!((BorderBits)borderStyle).sizable || state == minimized)
294 if(((BorderBits)borderStyle).contour && !((BorderBits)borderStyle).fixed)
301 // Reduce client area
309 void ShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving)
311 bool isNormal = (state == normal);
312 int top = 0, border = 0, bottom = 0;
313 Window parentMenuBar = GetParentMenuBar();
315 if(nativeDecorations && rootWindow == this && windowHandle) return;
317 if(state == minimized)
318 top = border = bottom = DEAD_BORDER;
319 else if(((BorderBits)borderStyle).sizable)
321 top = isNormal ? TOP : 0;
322 border = isNormal ? BORDER : 0;
325 else if(((BorderBits)borderStyle).fixed)
328 border = DEAD_BORDER;
329 bottom = DEAD_BORDER;
331 else if(((BorderBits)borderStyle).contour)
338 if(((BorderBits)borderStyle).deep || ((BorderBits)borderStyle).bevel)
340 int deepTop = 0, deepBottom = 0, deepBorder = 0;
341 if(((BorderBits)borderStyle).contour)
344 deepTop = (((BorderBits)borderStyle).fixed && (state != maximized || !parentMenuBar)) ? (top + CAPTION) : top;
345 deepBottom = (((BorderBits)borderStyle).sizable && isNormal) ? bottom : border;
348 surface.Bevel(((BorderBits)borderStyle).bevel ? false : true, deepBorder, deepTop,
349 size.w - deepBorder - deepBorder, size.h - deepBottom - deepTop);
352 if(((BorderBits)borderStyle).fixed && (state != maximized || !parentMenuBar))
354 if(state != maximized || !((BorderBits)borderStyle).sizable)
356 // Frame for ES_CAPTION windows
357 surface.Bevel(false, 0, 0, size.w, size.h);
358 surface.SetForeground(formColor);
359 surface.Rectangle(2, 2, size.w-3, size.h-3);
361 // Resizeable frame is 1 pixel thicker
362 if(((BorderBits)borderStyle).sizable && isNormal)
363 surface.Rectangle(3, 3, size.w - 4, size.h - 4);
368 surface.Gradient(gradient, sizeof(gradient) / sizeof(ColorKey), GRADIENT_SMOOTHNESS, GRADIENT_DIRECTION,
369 border, top, size.w - border - 1, top + CAPTION - 2);
371 surface.Gradient(gradientInactive, sizeof(gradientInactive) / sizeof(ColorKey),
372 GRADIENT_SMOOTHNESS, GRADIENT_DIRECTION,
373 border, top, size.w - border - 1, top + CAPTION - 2);
375 surface.SetForeground(formColor);
376 if(state != minimized)
377 surface.HLine(border, size.w-border-1, top + CAPTION-1);
379 surface.SetForeground((active ? TEXT_COLOR : TEXT_INACTIVE));
380 surface.TextOpacity(false);
381 surface.TextFont(captionFont);
384 int buttonsSize = border +
385 ((hasMaximize || hasMinimize) ? 52 : 18);
386 surface.WriteTextDots(left, border + NAME_OFFSETX, top + NAME_OFFSET,
387 size.w - (buttonsSize + border + 4), name, strlen(name));
390 if(((BorderBits)borderStyle).contour && !((BorderBits)borderStyle).fixed)
392 surface.SetForeground(black);
393 surface.Rectangle(0, 0, size.w - 1, size.h - 1);
396 if(state != minimized && hasHorzScroll && hasVertScroll)
398 if(sbh && sbh.visible && sbv && sbv.visible)
400 surface.SetBackground(formColor);
402 clientStart.x + clientSize.w,
403 clientStart.y + clientSize.h,
404 clientStart.x + clientSize.w + SB_WIDTH - 1,
405 clientStart.y + clientSize.h + SB_HEIGHT - 1);
410 bool IsMouseMoving(int x, int y, int w, int h)
412 bool isNormal = (state == normal);
414 if(nativeDecorations && rootWindow == this && windowHandle) return false;
416 if(((BorderBits\)borderStyle).fixed && (state != maximized || !GetParentMenuBar()))
418 int corner = 0, border = 0, top = 0;
419 if(((BorderBits)borderStyle).sizable && isNormal)
425 // Special case for having caption on resize bar
427 result = Box { corner, 0, w-corner-1, TOP-1 }.IsPointInside({x,y});
429 result = Box { border, top, w-border-1, top+CAPTION-1 }.IsPointInside({x, y});
434 bool IsMouseResizing(int x, int y, int w, int h, bool *resizeX, bool *resizeY, bool *resizeEndX, bool *resizeEndY)
438 *resizeX = *resizeY = *resizeEndX = *resizeEndY = false;
439 if(nativeDecorations && rootWindow == this && windowHandle) return false;
441 if(((BorderBits)borderStyle).sizable && (state == normal))
444 if(Box { 0, 0,CORNER-1, TOP-1 }.IsPointInside({x, y}))
445 result = *resizeX = *resizeY = true;
447 if(Box { w-CORNER-1, 0, w-1, TOP-1 }.IsPointInside({x, y}))
448 result = *resizeEndX = *resizeY = true;
450 if(Box { 0, h-BOTTOM-1, CORNER-1, h-1 }.IsPointInside({x, y}))
451 result = *resizeX = *resizeEndY = true;
452 // BottomRight Corner
453 if(Box { w-CORNER-1, h-BOTTOM-1, w-1, h-1 }.IsPointInside({x, y}))
454 result = *resizeEndX = *resizeEndY = true;
456 if(Box { 0,TOP, BORDER, h-BOTTOM-1 }.IsPointInside({x, y}))
457 result = *resizeX = true;
459 if(Box { w-BORDER-1, TOP, w-1, h-BOTTOM-1 }.IsPointInside({x, y}))
460 result = *resizeEndX = true;
462 if(Box { CORNER, 0, w-CORNER-1, TOP-1 }.IsPointInside({x, y}))
463 result = *resizeY = true;
465 if(Box { CORNER, h-BOTTOM-1, w-CORNER-1, h-1 }.IsPointInside({x, y}))
466 result = *resizeEndY = true;
471 void UpdateNonClient()
473 bool isNormal = (state == normal);
474 int top = 0, border = 0;
475 int insideBorder = 0;
477 if(!nativeDecorations || rootWindow != this || !windowHandle)
479 if(state == minimized)
480 top = border = DEAD_BORDER;
481 else if(((BorderBits)borderStyle).sizable)
483 if(state == maximized && GetParentMenuBar())
490 top = isNormal ? TOP : 0;
491 border = isNormal ? BORDER : 0;
494 else if(((BorderBits)borderStyle).fixed)
497 border = DEAD_BORDER;
499 else if(((BorderBits)borderStyle).contour)
504 insideBorder = border;
505 if(((BorderBits)borderStyle).deep)
510 border = clientStart.x;
511 insideBorder = border;
516 if(state == minimized)
517 menuBar.visible = false;
519 menuBar.visible = true;
520 menuBar.Move(clientStart.x, clientStart.y - skinMenuHeight, size.w - insideBorder * 2, skinMenuHeight);
524 if(state == minimized)
525 statusBar.visible = false;
528 statusBar.visible = true;
529 if(nativeDecorations && rootWindow == this && windowHandle)
531 statusBar.anchor = { left = clientStart.x, bottom = (int)(size.h - clientSize.h - clientStart.y - statusBarHeight ) };
532 statusBar.size.w = size.w - insideBorder * 2;
536 statusBar.anchor = { left = clientStart.x, bottom = border };
537 statusBar.size.w = size.w - insideBorder * 2;
541 if(!nativeDecorations || rootWindow != this || !windowHandle)
545 sysButtons[0].anchor = { right = 35 + border, top = top + BUTTON_OFFSET };
546 sysButtons[0].size = { 15, 15 };
547 sysButtons[0].bevel = true;
548 sysButtons[0].bitmap = { skinBitmaps[(state == minimized) ? restore : minimize] };
549 sysButtons[0].visible = true;
553 sysButtons[1].anchor = { right = 20 + border, top = top + BUTTON_OFFSET };
554 sysButtons[1].size = { 15, 15 };
555 sysButtons[1].bevel = true;
556 sysButtons[1].bitmap = { skinBitmaps[(state == maximized) ? restore : maximize] };
557 sysButtons[1].visible = true;
561 sysButtons[2].anchor = { right = 2 + border, top = top + BUTTON_OFFSET };
562 sysButtons[2].size = { 15, 15 };
563 sysButtons[2].bevel = true;
564 sysButtons[2].bitmap = { skinBitmaps[close] };
565 sysButtons[2].visible = true;
572 #define PUREVTBL(c) ((int (**)())*(void **)((byte *)class(c).data + 4))
573 #define CAPTION_DISTANCE 18
583 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnApplyGraphics;
584 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw;
587 public class WindowsSkin_Button : Button
589 void OnRedraw(Surface surface)
593 PUREVTBL(Button)[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw](this, surface);
598 ButtonState state = this.buttonState;
599 Bitmap buttonBitmap = bitmap ? bitmap.bitmap : null;
600 char * text = this.text;
601 int offset = (state == down && this.offset) ? 1 : 0;
602 Color backColor = background;
603 int isDefault = this.isDefault;
609 surface.TextFont(font);
611 surface.TextExtent(text, strlen(text),&tw, &th);
613 if(bevelOver && checked)
618 if(bitmaps[disabled]) buttonBitmap = bitmaps[disabled].bitmap;
622 if(buttonBitmap && buttonStyle.bevelOver && !buttonStyle.checkBox && !buttonStyle.radio && text)
626 if((bevel /*|| bevelOver*/) && opacity && backColor)
628 if(!scaleBitmap || !buttonBitmap)
630 ColorKey keys[2] = { { silver, 0.0f }, { white, 1.0f } };
631 surface.Gradient(keys, sizeof(keys) / sizeof(ColorKey), 1, vertical, 0, 0, clientSize.w-1, clientSize.h-1);
636 if(isCheckbox && !buttonBitmap)
639 int start = (clientSize.h - height) / 2;
642 // surface.SetBackground(formColor);
643 surface.SetBackground(gainsboro);
644 else if(active && !text)
645 surface.SetBackground((offset ? formColor : Color { 0,0,170 }));
647 surface.SetBackground((offset ? formColor : white));
648 surface.Area(2, start+2,height-3,start+height-3);
650 surface.SetForeground(Color { 85, 85, 85 });
651 surface.HLine(0, height - 2, start + 0);
652 surface.VLine(start+1, start+height - 2, 0);
654 surface.SetForeground(Color { 64,64,64 });
655 surface.HLine(1, height - 3, start + 1);
656 surface.VLine(start+2, start+height - 3, 1);
658 surface.SetForeground(Color { 212,208,200 });
659 surface.HLine(1, height - 2, start + height-2);
660 surface.VLine(start+1, start+height - 3, height-2);
662 surface.SetForeground(white);
663 surface.HLine(0, height - 1, start + height-1);
664 surface.VLine(start+0, start+height - 2, height-1);
669 surface.SetForeground(white);
671 surface.SetForeground(Color { 85, 85, 85 });
673 surface.SetForeground(black);
674 surface.DrawLine(4, start+8, 7,start+11);
675 surface.DrawLine(4, start+9, 7,start+12);
676 surface.DrawLine(7, start+11, 11,start+3);
677 surface.DrawLine(7, start+12, 11,start+4);
684 surface.SetForeground(white);
685 if(isRadio || isCheckbox)
687 int x = 0, y = (clientSize.h-buttonBitmap.height)/2;
688 if(bevelOver && text)
690 x = (CAPTION_DISTANCE-buttonBitmap.width)/2 + offset;
691 y = (clientSize.h-buttonBitmap.height)/2 + offset;
696 // Radio Buttons and Checkboxes
697 surface.Blit(buttonBitmap,
699 0,0,buttonBitmap.width,buttonBitmap.height);
707 surface.Stretch(buttonBitmap,
708 1 + offset, 1 + offset,0,0,
709 clientSize.w-3,clientSize.h-3,buttonBitmap.width,buttonBitmap.height);
711 surface.Stretch(buttonBitmap, 0,0, 0,0,
712 clientSize.w,clientSize.h,buttonBitmap.width,buttonBitmap.height);
717 bw = buttonBitmap.width;
718 bh = buttonBitmap.height;
720 if(bitmapAlignment == left || bitmapAlignment == right)
722 if(bitmapAlignment == left)
725 x = clientSize.w-bw-2;
726 y = (clientSize.h-bh)/2;
728 else if(bitmapAlignment == top || bitmapAlignment == bottom)
730 x = (clientSize.w-bw)/2;
731 if(bitmapAlignment == top)
734 y = clientSize.h-bh-2;
738 x = (clientSize.w-bw)/2;
739 y = (clientSize.h-bh - (int)(buttonStyle.bevelOver && text) * th)/2;
741 if(buttonStyle.bevel || buttonStyle.offset)
746 surface.Blit(buttonBitmap, x,y, 0,0, bw,bh);
752 if(bevel || (bevelOver && (state == down || state == over || checked)))
754 if(state == down || checked)
756 surface.SetForeground(Color { 85, 85, 85 });
757 surface.HLine(isDefault + 0, clientSize.w-2-isDefault, 0);
758 surface.VLine(isDefault + 1, clientSize.h-2-isDefault, 0);
759 surface.SetForeground(white);
760 surface.HLine(isDefault + 0, clientSize.w-1-isDefault, clientSize.h-1-isDefault);
761 surface.VLine(isDefault + 0, clientSize.h-2-isDefault, clientSize.w-1-isDefault);
765 surface.SetForeground(white);
766 surface.HLine(0 + isDefault, clientSize.w-2 - isDefault, isDefault);
767 surface.VLine(1 + isDefault, clientSize.h-2 - isDefault, isDefault);
768 surface.SetForeground(Color { 85, 85, 85 });
769 surface.HLine(1 + isDefault, clientSize.w-2 - isDefault, clientSize.h-2 - isDefault);
770 surface.VLine(1 + isDefault, clientSize.h-3 - isDefault, clientSize.w-2 - isDefault);
774 surface.SetForeground(black);
775 surface.HLine( isDefault, clientSize.w-1 - isDefault, clientSize.h-1 - isDefault);
776 surface.VLine( isDefault, clientSize.h-2 - isDefault, clientSize.w-1 - isDefault);
782 surface.TextOpacity(false);
783 surface.SetForeground(foreground);
787 surface.TextExtent(text, strlen(text),&tw, &th);
789 if((isRadio || isCheckbox) && !bevelOver)
790 WriteCaption(surface, CAPTION_DISTANCE + 3, // + clientSize.h,
791 (clientSize.h - th - 4)/2);
794 int x, y = (clientSize.h - th - 1)/2 + offset;
796 if(buttonStyle.bevelOver && buttonBitmap && !buttonStyle.checkBox && !buttonStyle.radio)
798 if(bitmapAlignment == top)
799 y = (clientSize.h - bh - 4 - th - 5)/2 + offset + bh + 4;
800 else if(bitmapAlignment == bottom)
801 y = (clientSize.h - bh - 4 - th - 5)/2 + offset;
802 else//if(bitmapAlignment == left || bitmapAlignment == right)
803 y = clientSize.h - th - 5 + offset;
806 y = (clientSize.h - th - 1)/2 + offset;
810 int width = clientSize.w - 2*6;
813 surface.WriteTextDots(alignment, x, y, width, text, strlen(text));
817 int width = clientSize.w - 2 * 6;
819 if(bitmapAlignment == left || bitmapAlignment == right)
821 if(bitmapAlignment == left)
825 if(isCheckbox || ((isRadio /*|| bevelOver*/) && buttonBitmap))
827 x += CAPTION_DISTANCE + 3;
832 if(alignment == right)
834 else if(alignment == center)
835 x += (width - tw) / 2;
837 WriteCaption(surface, x, y);
842 // Activation Highlight
845 surface.SetForeground(black);
846 surface.Rectangle(0,0,clientSize.w-1,clientSize.h-1);
848 if(!bevelOver && !isRemote)
850 if(active) // && (text || !(buttonStyle.radio || buttonStyle.checkBox)))
853 surface.SetForeground(black);
854 surface.LineStipple(0x5555);
856 if((isRadio || isCheckbox) && text)
858 x1 = CAPTION_DISTANCE; // + clientSize.h;
867 x2 = clientSize.w - 5+offset;
868 y2 = clientSize.h - 5+offset;
870 if(isRadio || isCheckbox)
878 if((x2 - x1) & 1) x2++;
879 if((y2 - y1) & 1) y2++;
881 surface.Rectangle(x1, y1, x2, y2);
882 surface.LineStipple(0);