Skip to content

Instantly share code, notes, and snippets.

@lighth7015
Created January 8, 2020 21:44
Show Gist options
  • Save lighth7015/4bfad2b5f387dc0c5f22b5bc33f87cd6 to your computer and use it in GitHub Desktop.
Save lighth7015/4bfad2b5f387dc0c5f22b5bc33f87cd6 to your computer and use it in GitHub Desktop.
eC Windows NT/9x theme
public import "ecere"
public import "ecere.gui.controls"
define skinBackground = Color { r = 192, g = 192, b = 192 };
define skinForeground = black;
define skinTextForeground = black;
define evenRowBackground = Color { 80, 70, 60 };
define selectionColor = blue;
static const char * buttonStates[SkinBitmap] = {
"<:ecere>elements/areaMinimize.png",
"<:ecere>elements/areaMaximize.png",
"<:ecere>elements/areaRestore.png",
"<:ecere>elements/areaClose.png"
};
#define BORDER 2
#define TOP 2
#define BOTTOM 2
#define CORNER (BORDER * 2)
#define CAPTION 25
#define DEAD_BORDER 2
#define MIN_WIDTH 60
#define MIN_HEIGHT 3
#define BUTTON_OFFSET (TOP + DEAD_BORDER)
#define NAME_OFFSET 0
#define NAME_OFFSETX 4
#define SB_WIDTH 16
#define SB_HEIGHT 16
#define MENU_HEIGHT CAPTION
#define STATUS_HEIGHT 18
#define TEXT_COLOR white
#define TEXT_INACTIVE darkGray
#define FONT_NAME "Source Sans Pro"
#define PUREVTBL(c) ((int (**)())*(void **)((byte *)class(c).data + sizeof(void *)))
#define THUNK_CALL7(type, name, event, ...) \
(void*)(PUREVTBL(type)[ __ecereVMethodID___ecereNameSpace__ecere__gui__##name##_##event ])(this, __VA_ARGS__)
#define THUNK_CALL4(type, name, event, ...) \
(void*)(PUREVTBL(type)[ __ecereVMethodID___ecereNameSpace__ecere__gui__##name##_##event ])(this, __VA_ARGS__)
#define THUNK_CALL3(type, name, event) \
(void*)(PUREVTBL(type)[ __ecereVMethodID___ecereNameSpace__ecere__gui__##name##_##event ])(this)
#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define THUNK_CALL_IMPL2(count, ...) THUNK_CALL ## count (__VA_ARGS__)
#define THUNK_CALL_IMPL(count, ...) THUNK_CALL_IMPL2(count, __VA_ARGS__)
#define THUNK_CALL(...) THUNK_CALL_IMPL(VA_NARGS(__VA_ARGS__), __VA_ARGS__)
class AppSkin_Window : Window {
void ShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving) {
bool isNormal = (state == normal || state == maximized);
surface.TextFont(captionFont);
int top = 0, border = 0, bottom = 0;
surface.background = Color { 191, 191, 191 };
//surface.Area(0, 0, size.w, size.h);
if(state == minimized)
top = border = bottom = DEAD_BORDER;
else if(((BorderBits)borderStyle).sizable)
{
top = isNormal ? TOP : 0;
border = isNormal ? BORDER : 0;
bottom = BOTTOM;
}
else if(((BorderBits)borderStyle).fixed)
{
top = 2; //DEAD_BORDER;
border = DEAD_BORDER;
bottom = DEAD_BORDER;
}
else if(((BorderBits)borderStyle).contour)
{
top = 1;
border = 1;
bottom = 1;
}
if(((BorderBits)borderStyle).deep || ((BorderBits)borderStyle).bevel)
{
int deepTop = 0, deepBottom = 0, deepBorder = 0;
if(((BorderBits)borderStyle).contour)
{
deepBorder = border;
deepTop = (((BorderBits)borderStyle).fixed && (state != maximized || !parent.menuBar)) ? (top + CAPTION) : top;
deepBottom = (((BorderBits)borderStyle).sizable && isNormal) ? bottom : border;
}
surface.Bevel(((BorderBits)borderStyle).bevel ? false : true, deepBorder, deepTop,
size.w - deepBorder - deepBorder, size.h - deepBottom - deepTop);
}
if(((BorderBits)borderStyle).fixed && (state != maximized || !parent.menuBar))
{
surface.SetBackground(Color { r = 192, g = 192, b = 192 });
surface.Area(0, 0, size.w, CAPTION + 2 );
surface.Bevel(false, 0, 0, size.w, size.h);
surface.SetBackground(Color { r = 128, g = 128, b = 128 });
// Caption
if(active) {
surface.SetBackground(Color { r = 0, g = 0, b = 132 });
surface.SetForeground(white);
}
else {
surface.SetForeground(Color { r = 192, g = 192, b = 192 });
}
int borderOffs = CAPTION - MIN_HEIGHT;
surface.Area( border + ( border / 2 ) + 1, border + ( border / 2 ) + 1, size.w - ( border + 2 ) - 1, borderOffs );
surface.SetForeground(TEXT_COLOR);
//surface.alphaWrite = write;
surface.WriteTextDots(left, 5, top + (top / 2), size.w, name, strlen(name));
surface.SetBackground(Color { r = 192, g = 192, b = 192 });
/*
if(state != maximized || !((BorderBits)borderStyle).sizable)
{
// Frame for ES_CAPTION windows
surface.Bevel(false, 0, 0, size.w, size.h);
surface.SetForeground(activeBorder);
surface.Rectangle(2, 2, size.w-3, size.h-3);
// Resizeable frame is 1 pixel thicker
if(((BorderBits)borderStyle).sizable && isNormal)
surface.Rectangle(3, 3, size.w - 4, size.h - 4);
}
// Caption
if(active)
surface.Gradient(gradient, sizeof(gradient) / sizeof(ColorKey), GRADIENT_SMOOTHNESS, GRADIENT_DIRECTION,
border, top, size.w - border - 1, top + CAPTION - 2);
else
surface.Gradient(gradientInactive, sizeof(gradientInactive) / sizeof(ColorKey),
GRADIENT_SMOOTHNESS, GRADIENT_DIRECTION,
border, top, size.w - border - 1, top + CAPTION - 2);
surface.SetForeground(activeBorder);
if(state != minimized)
surface.HLine(border, size.w-border-1, top + CAPTION-1);
*
surface.SetForeground(skinBackground);
surface.Rectangle(0,0, size.w-1, size.h-1);
surface.SetForeground(active ? TEXT_COLOR : TEXT_INACTIVE **skinForeground**);
/*
surface.Rectangle(1,1, size.w-2, size.h-2);
surface.SetBackground(skinBackground);
surface.Area(2, 2, size.w-3, CAPTION + 2);
// surface.TextFont(captionFont);
// surface.WriteText(4,2, name, strlen(name));
surface.SetForeground((active ? TEXT_COLOR : TEXT_INACTIVE));
surface.TextOpacity(false);
surface.TextFont(captionFont);
if(name)
{
int buttonsSize = border +
((hasMaximize || hasMinimize) ? 52 : 18);
surface.WriteTextDots(left, border + NAME_OFFSETX, top + NAME_OFFSET,
size.w - (buttonsSize + border + 4), name, strlen(name));
}
*/
}
if(((BorderBits)borderStyle).contour && !((BorderBits)borderStyle).fixed)
{
surface.SetForeground(skinForeground /*black*/);
surface.Rectangle(0, 0, size.w - 1, size.h - 1);
}
if(state != minimized && hasHorzScroll && hasVertScroll)
{
if(sbh && sbh.visible && sbv && sbv.visible)
{
surface.SetBackground(activeBorder);
surface.Area(
clientStart.x + clientSize.w,
clientStart.y + clientSize.h,
clientStart.x + clientSize.w + SB_WIDTH - 1,
clientStart.y + clientSize.h + SB_HEIGHT - 1);
}
}
}
void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h) {
*w = *h = 0;
if((((BorderBits)borderStyle).deep || ((BorderBits)borderStyle).bevel) && state != minimized)
{
*w += 4;
*h += 4;
}
if(((BorderBits)borderStyle).sizable && (state == normal || state == maximized))
{
*w += 2 * BORDER;
*h += TOP + BOTTOM;
}
if(((BorderBits)borderStyle).fixed && (state != maximized || !parent.menuBar))
{
*h += CAPTION;
if(!((BorderBits)borderStyle).sizable || state == minimized)
{
*h += 2*DEAD_BORDER;
*w += 2*DEAD_BORDER;
}
}
if(((BorderBits)borderStyle).contour && !((BorderBits)borderStyle).fixed)
{
*w += 2;
*h += 2;
}
if(hasMenuBar && state != minimized) {
*h += MENU_HEIGHT;
}
if(statusBar && state != minimized) {
*h += STATUS_HEIGHT;
}
}
bool IsMouseMoving(int x, int y, int w, int h)
{
BorderBits style = (BorderBits)borderStyle; // TOFIX: borderStyle.fixed doesn't work
if(style.fixed)
{
bool resizeX, resizeY, resizeEndX, resizeEndY;
if(!IsMouseResizing(x, y, w, h, &resizeX, &resizeY, &resizeEndX, &resizeEndY))
return true;
}
return false;
}
bool IsMouseResizing(int x, int y, int w, int h, bool *resizeX, bool *resizeY, bool *resizeEndX, bool *resizeEndY) {
bool result = false;
*resizeX = *resizeY = *resizeEndX = *resizeEndY = false;
if(((BorderBits)borderStyle).sizable && (state == normal))
{
// TopLeft Corner
if(Box { 0, 0,CORNER-1, TOP-1 }.IsPointInside({x, y}))
result = *resizeX = *resizeY = true;
// TopRight Corner
if(Box { w-CORNER-1, 0, w-1, TOP-1 }.IsPointInside({x, y}))
result = *resizeEndX = *resizeY = true;
// BottomLeft Corner
if(Box { 0, h-BOTTOM-1, CORNER-1, h-1 }.IsPointInside({x, y}))
result = *resizeX = *resizeEndY = true;
// BottomRight Corner
if(Box { w-CORNER-1, h-BOTTOM-1, w-1, h-1 }.IsPointInside({x, y}))
result = *resizeEndX = *resizeEndY = true;
// Left Border
if(Box { 0,TOP, BORDER, h-BOTTOM-1 }.IsPointInside({x, y}))
result = *resizeX = true;
// Right Border
if(Box { w-BORDER-1, TOP, w-1, h-BOTTOM-1 }.IsPointInside({x, y}))
result = *resizeEndX = true;
// Top Border
if(Box { CORNER, 0, w-CORNER-1, TOP-1 }.IsPointInside({x, y}))
result = *resizeY = true;
// Bottom Border
if(Box { CORNER, h-BOTTOM-1, w-CORNER-1, h-1 }.IsPointInside({x, y}))
result = *resizeEndY = true;
}
return result;
}
void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh)
{
bool isNormal = (state == normal || state == maximized);
if(((BorderBits)borderStyle).fixed && (state != maximized || !parent.menuBar))
{
*mw = MIN_WIDTH;
*mh = MIN_HEIGHT;
}
else
*mw = *mh = 0;
/*
if(((BorderBits)borderStyle).sizable && isNormal)
*mw += 2*CORNER;
// GetDecorationsSize(window, mw, mh);
*/
if(hasVertScroll)
*mw += SB_WIDTH;
if(hasHorzScroll)
*mh += SB_HEIGHT;
if(hasVertScroll && hasHorzScroll)
{
*mw += 2 * SB_WIDTH + SB_WIDTH;
*mh += 2 * SB_HEIGHT + SB_HEIGHT;
if(((BorderBits)borderStyle).sizable && isNormal)
*mw -= 2*CORNER;
}
}
void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch) {
bool isNormal = (state == normal || state == maximized);
MinMaxValue aw = 0, ah = 0;
*x = *y = 0;
GetDecorationsSize(&aw, &ah);
// Compute client area start
if(((BorderBits)borderStyle).deep || ((BorderBits)borderStyle).bevel) {
*x += 2;
*y += 2;
}
if(((BorderBits)borderStyle).sizable && isNormal) {
*x += BORDER;
*y += TOP;
}
if(hasMenuBar) {
*y += MENU_HEIGHT;
}
if(((BorderBits)borderStyle).fixed && (state != maximized || !parent.menuBar)) {
*y += CAPTION;
if(!((BorderBits)borderStyle).sizable || state == minimized) {
*y += DEAD_BORDER;
*x += DEAD_BORDER;
}
}
if(((BorderBits)borderStyle).contour && !((BorderBits)borderStyle).fixed) {
*x += 1;
*y += 1;
}
// Reduce client area
*cw = *w - aw;
*ch = *h - ah;
*cw = Max(*cw, 0);
*ch = Max(*ch, 0);
}
void UpdateNonClient() {
bool isNormal = (state == normal || state == maximized);
int top = 0, border = 0;
int insideBorder;
if(state == minimized) {
top = border = DEAD_BORDER;
}
else if(((BorderBits)borderStyle).sizable) {
if(state == maximized && parent.menuBar) {
top = 2;
border = 2;
}
else {
top = isNormal ? TOP : 0;
border = isNormal ? BORDER : 0;
}
}
else if(((BorderBits)borderStyle).fixed) {
top = 2;
border = 2;
}
else if(((BorderBits)borderStyle).contour) {
top = 1;
border = 1;
}
insideBorder = border;
if(((BorderBits)borderStyle).deep) {
insideBorder += 2;
}
if(menuBar) {
if(state == minimized) {
menuBar.visible = false;
}
else {
menuBar.visible = true;
}
menuBar.Move(clientStart.x, clientStart.y - MENU_HEIGHT, size.w, MENU_HEIGHT);
menuBar.background = Color { 191, 191, 191 };
menuBar.borderStyle = none;
}
if(statusBar) {
if(state == minimized) {
statusBar.visible = false;
}
else {
statusBar.visible = true;
statusBar.anchor = { left = clientStart.x, bottom = border };
statusBar.size.w = size.w - insideBorder * 2;
}
}
Size wbCtlSize = { 16, 14 };
Color wbCtlBgc = Color { 192, 192, 192 };
int offsetRight = 22,
buttonOffYp = DEAD_BORDER + top + 3;
maximizeButton.visible = true;
if(minimizeButton) {
minimizeButton.anchor = {
right = offsetRight + wbCtlSize.w + border,
top = buttonOffYp
};
minimizeButton.size = wbCtlSize;
minimizeButton.foreground = black;
minimizeButton.background = wbCtlBgc;
minimizeButton.bitmap = { buttonStates[(state == minimized) ? restore : minimize] };
minimizeButton.bevel = true;
minimizeButton.visible = true;
}
if(maximizeButton) {
maximizeButton.anchor = { right = offsetRight + border, top = buttonOffYp };
maximizeButton.size = wbCtlSize;
maximizeButton.bevel = true;
maximizeButton.foreground = black;
maximizeButton.background = wbCtlBgc;
maximizeButton.bitmap = { buttonStates[(state == maximized) ? restore : maximize] };
}
if(closeButton) {
closeButton.anchor = { right = (DEAD_BORDER + (border * 2)), top = buttonOffYp };
closeButton.size = wbCtlSize;
closeButton.bevel = true;
closeButton.foreground = black;
closeButton.background = wbCtlBgc;
closeButton.bitmap = { buttonStates[close] };
closeButton.visible = true;
}
}
void OnApplyGraphics() {
background = Color { 191, 191, 191 };
foreground = skinForeground;
}
}
class AppSkin_StatusBar : StatusBar {
void OnApplyGraphics() {
background = skinBackground;
foreground = skinForeground;
}
}
class AppSkin_FileDialog : FileDialog {
void OnApplyGraphics() {
Window child;
background = skinBackground;
foreground = skinForeground;
for(child = firstChild; child; child = child.next) {
if(!child.opacity)
child.foreground = skinForeground;
}
}
}
extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnApplyGraphics;
extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw;
static void Dummy() {
Window a;
a.OnApplyGraphics();
a.OnRedraw(null);
}
class AppSkin_Button : Button {
void OnApplyGraphics() {
background = Color { 191, 191, 191 };
foreground = black;
}
void OnRedraw(Surface surface) {
int isDefault = (int)this.isDefault;
THUNK_CALL(Button, Window, OnRedraw, surface);
if(bevel || (bevelOver && (buttonState == down || buttonState == over || checked))) {
Color c = steelBlue;
if(buttonState == down || checked)
{
surface.SetForeground(black);
surface.HLine(isDefault + 0, clientSize.w-2-isDefault, 0);
surface.VLine(isDefault + 1, clientSize.h-2-isDefault, 0);
surface.SetForeground(white);
surface.HLine(isDefault + 0, clientSize.w-1-isDefault, clientSize.h-1-isDefault);
surface.VLine(isDefault + 0, clientSize.h-2-isDefault, clientSize.w-1-isDefault);
}
else {
surface.SetForeground(white);
surface.HLine(0 + isDefault, clientSize.w-2 - isDefault, isDefault);
surface.VLine(1 + isDefault, clientSize.h-2 - isDefault, isDefault);
surface.SetForeground(Color{ 127, 127, 127 });
if(bevel) {
surface.HLine(1 + isDefault, (clientSize.w - 3) - isDefault, (clientSize.h - 2) - isDefault);
surface.VLine(1 + isDefault, (clientSize.h - 3) - isDefault, (clientSize.w - 2) - isDefault);
surface.SetForeground(Color{ 223, 223, 223 });
surface.HLine(1 + isDefault, clientSize.w - 3 - isDefault, isDefault + 1);
surface.VLine(1 + isDefault, clientSize.h - 3 - isDefault, isDefault + 1);
surface.SetForeground(black);
surface.HLine( isDefault, clientSize.w-1 - isDefault, clientSize.h-1 - isDefault);
surface.VLine( isDefault, clientSize.h-2 - isDefault, clientSize.w-1 - isDefault);
}
else {
surface.SetForeground(black);
surface.HLine(1 + isDefault, clientSize.w-2 - isDefault, clientSize.h-2 - isDefault);
surface.VLine(1 + isDefault, clientSize.h-3 - isDefault, clientSize.w-2 - isDefault);
surface.HLine( isDefault, clientSize.w-1 - isDefault, clientSize.h-1 - isDefault);
surface.VLine( isDefault, clientSize.h-2 - isDefault, clientSize.w-1 - isDefault);
}
}
if(!(bevelOver) && !isRemote) {
if(active) {
int x1,y1,x2,y2;
int triplet = 96;
int offset = (buttonState == down && this.offset) ? 1 : 0;
surface.SetForeground(Color { triplet, triplet, triplet });
surface.LineStipple(0xFFFFF);
#define CAPTION_DISTANCE 18
x2 = clientSize.w;
y2 = clientSize.h;
if((isRadio || isCheckbox) && text) {
x1 = /*clientSize.h + */CAPTION_DISTANCE;
y1 = 0;
x2 -= 4;
y2 -= 4;
}
else {
if(isRadio || isCheckbox) {
x1-=3;
y1-=3;
x2+=1;
y2+=1;
}
else {
x1 = 3 + offset;
y1 = 3 + offset;
x2 -= 4;
y2 -= 4;
}
}
surface.Rectangle(x1, y1, x2, y2);
surface.LineStipple(0);
}
if(isDefault) {
surface.SetForeground(Color { 128, 128, 128 });
surface.Rectangle(0,0,clientSize.w-1,clientSize.h-1);
}
}
}
}
}
class AppSkin_ScrollBar : ScrollBar {
private bool upBtnActive,
dnBtnActive;
public:
AppSkin_ScrollBar() {
upBtnActive = false;
dnBtnActive = false;
}
void OnApplyGraphics() {
THUNK_CALL(ScrollBar, Window, OnApplyGraphics);
background = { 223, 223, 223 };
foreground = black;
Color scrBtnBg { 165, 165, 165 };
downBtn.background = scrBtnBg;
downBtn.foreground = black;
upBtn.background = downBtn.background;
thumb.background = upBtn.background;
//.bitmap = { "<:ecere>elements/arrowLeft.png" };
upBtn.OnRedraw = UpThumbRePaint;
upBtn.NotifyPushed = NotifyUpBtnEnter;
upBtn.NotifyReleased = NotifyUpBtnLeave;
downBtn.NotifyPushed = NotifyDnBtnEnter;
downBtn.NotifyReleased = NotifyDnBtnLeave;
// { "<:ecere>elements/arrowRight.png" };
downBtn.OnRedraw = DnThumbRePaint;
}
bool NotifyUpBtnEnter(Button button, int x, int y, Modifiers mods) {
bool success = Button::NotifyPushed(this, button, x, y, mods);
upBtnActive = true;
return success;
}
bool NotifyUpBtnLeave(Button button, int x, int y, Modifiers mods) {
bool success = Button::NotifyPushed(this, button, x, y, mods);
upBtnActive = false;
return success;
}
bool NotifyDnBtnEnter(Button button, int x, int y, Modifiers mods) {
bool success = Button::NotifyPushed(this, button, x, y, mods);
dnBtnActive = true;
return success;
}
bool NotifyDnBtnLeave(Button button, int x, int y, Modifiers mods) {
bool success = Button::NotifyPushed(this, button, x, y, mods);
dnBtnActive = false;
return success;
}
void BaseRepaint(Surface surface, bool pressed) {
THUNK_CALL(Button, Window, OnRedraw, surface);
if (pressed) {
surface.Area(1, 1, size.w - 2, size.h - 2);
}
}
void UpThumbRePaint(Surface surface) {
BaseRepaint(surface, upBtnActive);
}
void DnThumbRePaint(Surface surface) {
BaseRepaint(surface, dnBtnActive);
}
}
class AppSkin_DropBox : DropBox {
void OnApplyGraphics() {
THUNK_CALL(DropBox, Window, OnApplyGraphics);
Color scrBtnBg { 165, 165, 165 };
button.bitmap = { "<:ecere>elements/arrowDown.png", monochrome = true };
background = scrBtnBg;
foreground = white;
selectionColor = Color { 0, 0, 128 };
selectionText = white;
}
}
class AppSkin_ListBox : ListBox {
void OnApplyGraphics() {
THUNK_CALL(ListBox, Window, OnApplyGraphics);
background = skinBackground;
foreground = skinForeground;
this.selectionColor = ::selectionColor;
}
}
public class AppSkin : Skin {
class_property(name) = "App";
class_property(selectionColor) = (Color) white;
class_property(disabledBackColor) = Color { 0, 0, 0 };
class_property(disabledFrontColor) = Color { 75, 75, 75 };
FontResource ::SystemFont() {
return { faceName = FONT_NAME, size = 11.5f };
}
FontResource ::CaptionFont() {
return { faceName = FONT_NAME, size = 11.5f, true };
}
char * ::CursorsBitmaps(uint id, int *hotSpotX, int *hotSpotY, byte ** paletteShades) {
return null;
}
BitmapResource ::GetBitmap(int id) {
return null;
}
int ::VerticalSBW() {
return 16;
}
int ::HorizontalSBH() {
return 16;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment