ecere: Android fixes; i18n update
[sdk] / ecere / src / gui / skins / WindowsSkin.ec
index 7a35ea0..5d240ac 100644 (file)
@@ -1,30 +1,47 @@
-namespace gui::skins;
-
 #if defined(WIN32)
 #define WIN32_LEAN_AND_MEAN
+#define String _String
 #define Method _Method
+#define strlen _strlen
 #include <windows.h>
 #undef Method
+#undef String
+#undef strlen
 #endif
 
 import "Window"
 
+#if !defined(WIN32)
+bool gui::drivers::XGetBorderWidths(Window window, Box box);
+#endif
+
+namespace gui::skins;
+
 #define BORDER       4
 #define TOP          4
 #define BOTTOM       4
 #define CORNER       (BORDER * 2)
+#if defined(HIGH_DPI)
+#define BUTTON_SIZE  45
+#define CAPTION      60
+#else
+#define BUTTON_SIZE  15
 #define CAPTION      20
+#endif
 #define DEAD_BORDER  3
 #define MIN_WIDTH    60
 #define MIN_HEIGHT   3
 #define BUTTON_OFFSET   2
+#if defined(HIGH_DPI)
+#define NAME_OFFSET   12
+#else
 #define NAME_OFFSET   2
+#endif
 #define NAME_OFFSETX  4
 
 #define SB_WIDTH  16
 #define SB_HEIGHT 16
 
-#define STATUS_HEIGHT   18
 
 #define GRADIENT_SMOOTHNESS 1.0f
 
@@ -119,12 +136,20 @@ class WindowsSkin : Skin
 
    FontResource ::SystemFont()
    {
-      return FontResource { faceName = "Tahoma", size = 8.25f };
+#if defined(HIGH_DPI)
+      return FontResource { faceName = $"Tahoma", size = 18.25f };
+#else
+      return FontResource { faceName = $"Tahoma", size = 8.25f };
+#endif
    }
 
    FontResource ::CaptionFont()
    {
-      return FontResource { faceName = "Tahoma", size = 8.25f, bold = true };
+#if defined(HIGH_DPI)
+      return FontResource { faceName = $"Tahoma", size = 18.25f, bold = true };
+#else
+      return FontResource { faceName = $"Tahoma", size = 8.25f, bold = true };
+#endif
    }
 
    char * ::CursorsBitmaps(uint id, int * hotSpotX, int *hotSpotY, byte ** paletteShades)
@@ -157,19 +182,27 @@ public class WindowsSkin_Window : Window
       }
       if(statusBar && state != minimized)
       {
-         *h += STATUS_HEIGHT;
+         *h += statusBarHeight;
       }
 
-      if(nativeDecorations && rootWindow == this)
+      if(nativeDecorations && rootWindow == this && windowHandle)
       {
 #if defined(WIN32)
-         RECT rcClient, rcWindow;
-         GetClientRect(windowHandle, &rcClient);
-         GetWindowRect(windowHandle, &rcWindow);
-         *w += (rcWindow.right - rcWindow.left) - rcClient.right;
-         *h += (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
+         RECT rcClient = { 0 }, rcWindow = { 0 };
+         if(GetClientRect(windowHandle, &rcClient) && GetWindowRect(windowHandle, &rcWindow))
+         {
+            *w += (rcWindow.right - rcWindow.left) - rcClient.right;
+            *h += (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
+         }
 
          // PrintLn(_class.name, " is at l = ", rcWindow.left, ", r = ", rcWindow.right);
+#else
+         Box widths = { 0 };
+#if !defined(__ANDROID__)
+         XGetBorderWidths(this, widths);
+#endif
+         *w += widths.left + widths.right;
+         *h += widths.top + widths.bottom;
 #endif
          return;
       }
@@ -183,7 +216,7 @@ public class WindowsSkin_Window : Window
          *w += 2 * BORDER;
          *h += TOP + BOTTOM;
       }
-      if(((BorderBits)borderStyle).fixed && (state != maximized || !parent.menuBar))
+      if(((BorderBits)borderStyle).fixed && (state != maximized || !GetParentMenuBar()))
       {
          *h += CAPTION;
          if(!((BorderBits)borderStyle).sizable || state == minimized)
@@ -202,8 +235,8 @@ public class WindowsSkin_Window : Window
    void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh)
    {
       bool isNormal = (state == normal);
-      if(nativeDecorations && rootWindow == this) return;
-      if(((BorderBits)borderStyle).fixed && (state != maximized || !parent.menuBar))
+      if(nativeDecorations && rootWindow == this && windowHandle) return;
+      if(((BorderBits)borderStyle).fixed && (state != maximized || !GetParentMenuBar()))
       {
          *mw = MIN_WIDTH;
          *mh = MIN_HEIGHT;
@@ -241,7 +274,7 @@ public class WindowsSkin_Window : Window
 
       GetDecorationsSize(&aw, &ah);
 
-      if(nativeDecorations && rootWindow == this)
+      if(nativeDecorations && rootWindow == this && windowHandle)
       {
 #if defined(WIN32)
          RECT rcWindow;
@@ -250,6 +283,13 @@ public class WindowsSkin_Window : Window
          GetWindowRect(windowHandle, &rcWindow);
          *x += client00.x - rcWindow.left;
          *y += client00.y - rcWindow.top;
+#else
+         Box widths = { 0 };
+#if !defined(__ANDROID__)
+         XGetBorderWidths(this, widths);
+#endif
+         *x += widths.left;
+         *y += widths.top;
 #endif
       }
       else
@@ -267,7 +307,7 @@ public class WindowsSkin_Window : Window
             *y += TOP;
          }
 
-         if(((BorderBits)borderStyle).fixed && (state != maximized || !parent.menuBar))
+         if(((BorderBits)borderStyle).fixed && (state != maximized || !GetParentMenuBar()))
          {
             *y += CAPTION;
             if(!((BorderBits)borderStyle).sizable || state == minimized)
@@ -296,8 +336,9 @@ public class WindowsSkin_Window : Window
    {
       bool isNormal = (state == normal);
       int top = 0, border = 0, bottom = 0;
+      Window parentMenuBar = GetParentMenuBar();
 
-      if(nativeDecorations && rootWindow == this) return;
+      if(nativeDecorations && rootWindow == this && windowHandle) return;
 
       if(state == minimized)
          top = border = bottom = DEAD_BORDER;
@@ -326,7 +367,7 @@ public class WindowsSkin_Window : Window
          if(((BorderBits)borderStyle).contour)
          {
             deepBorder = border;
-            deepTop = (((BorderBits)borderStyle).fixed && (state != maximized || !parent.menuBar)) ? (top + CAPTION) : top;
+            deepTop = (((BorderBits)borderStyle).fixed && (state != maximized || !parentMenuBar)) ? (top + CAPTION) : top;
             deepBottom = (((BorderBits)borderStyle).sizable && isNormal) ? bottom : border;
          }
 
@@ -334,13 +375,13 @@ public class WindowsSkin_Window : Window
             size.w - deepBorder - deepBorder, size.h - deepBottom - deepTop);
       }
 
-      if(((BorderBits)borderStyle).fixed && (state != maximized || !parent.menuBar))
+      if(((BorderBits)borderStyle).fixed && (state != maximized || !parentMenuBar))
       {
          if(state != maximized || !((BorderBits)borderStyle).sizable)
          {
             // Frame for ES_CAPTION windows
             surface.Bevel(false, 0, 0, size.w, size.h);
-            surface.SetForeground(activeBorder);
+            surface.SetForeground(formColor);
             surface.Rectangle(2, 2, size.w-3, size.h-3);
 
             // Resizeable frame is 1 pixel thicker 
@@ -357,7 +398,7 @@ public class WindowsSkin_Window : Window
             GRADIENT_SMOOTHNESS, GRADIENT_DIRECTION,
                border, top, size.w - border - 1, top + CAPTION - 2);
 
-         surface.SetForeground(activeBorder);
+         surface.SetForeground(formColor);
          if(state != minimized)
             surface.HLine(border, size.w-border-1, top + CAPTION-1);
 
@@ -367,7 +408,7 @@ public class WindowsSkin_Window : Window
          if(name)
          {
             int buttonsSize = border +
-               ((hasMaximize || hasMinimize) ? 52 : 18);
+               ((hasMaximize || hasMinimize) ? (BUTTON_SIZE*3)+7 : (BUTTON_SIZE+3));
             surface.WriteTextDots(left, border + NAME_OFFSETX, top + NAME_OFFSET, 
                size.w - (buttonsSize + border + 4), name, strlen(name));
          }
@@ -382,7 +423,7 @@ public class WindowsSkin_Window : Window
       {
          if(sbh && sbh.visible && sbv && sbv.visible)
          {
-            surface.SetBackground(activeBorder);
+            surface.SetBackground(formColor);
             surface.Area(
                clientStart.x + clientSize.w,
                clientStart.y + clientSize.h,
@@ -396,9 +437,9 @@ public class WindowsSkin_Window : Window
    {
       bool isNormal = (state == normal);
       bool result = false;
-      if(nativeDecorations && rootWindow == this) return false;
+      if(nativeDecorations && rootWindow == this && windowHandle) return false;
 
-      if(((BorderBits)borderStyle).fixed && (state != maximized || !parent.menuBar))
+      if(((BorderBits)borderStyle).fixed && (state != maximized || !GetParentMenuBar()))
       {
          int corner = 0, border = 0, top = 0;
          if(((BorderBits)borderStyle).sizable && isNormal)
@@ -421,7 +462,7 @@ public class WindowsSkin_Window : Window
       bool result = false;
 
       *resizeX = *resizeY = *resizeEndX = *resizeEndY = false;
-      if(nativeDecorations && rootWindow == this) return false;
+      if(nativeDecorations && rootWindow == this && windowHandle) return false;
 
       if(((BorderBits)borderStyle).sizable && (state == normal))
       {
@@ -459,13 +500,13 @@ public class WindowsSkin_Window : Window
       int top = 0, border = 0;
       int insideBorder = 0;
 
-      if(!nativeDecorations || rootWindow != this)
+      if(!nativeDecorations || rootWindow != this || !windowHandle)
       {
          if(state == minimized)
             top = border = DEAD_BORDER;
          else if(((BorderBits)borderStyle).sizable)
          {
-            if(state == maximized && parent.menuBar)
+            if(state == maximized && GetParentMenuBar())
             {
                top = 2;
                border = 2;
@@ -511,9 +552,9 @@ public class WindowsSkin_Window : Window
          else
          {
             statusBar.visible = true;
-            if(nativeDecorations && rootWindow == this)
+            if(nativeDecorations && rootWindow == this && windowHandle)
             {
-               statusBar.anchor = { left = clientStart.x, bottom = (int)(size.h - clientSize.h - clientStart.y - STATUS_HEIGHT ) };
+               statusBar.anchor = { left = clientStart.x, bottom = (int)(size.h - clientSize.h - clientStart.y - statusBarHeight ) };
                statusBar.size.w = size.w - insideBorder * 2;
             }
             else
@@ -523,20 +564,20 @@ public class WindowsSkin_Window : Window
             }
          }
       }
-      if(!nativeDecorations || rootWindow != this)
+      if(!nativeDecorations || rootWindow != this || !windowHandle)
       {
          if(sysButtons[0])
          {
-            sysButtons[0].anchor = { right = 35 + border, top = top + BUTTON_OFFSET };
-            sysButtons[0].size = { 15, 15 };
+            sysButtons[0].anchor = { right = 2+(2*BUTTON_SIZE+3) + border, top = top + BUTTON_OFFSET };
+            sysButtons[0].size = { BUTTON_SIZE, BUTTON_SIZE };
             sysButtons[0].bevel = true;
             sysButtons[0].bitmap = { skinBitmaps[(state == minimized) ? restore : minimize] };
             sysButtons[0].visible = true;
          }
          if(sysButtons[1])
          {
-            sysButtons[1].anchor = { right = 20 + border, top = top + BUTTON_OFFSET };
-            sysButtons[1].size = { 15, 15 };
+            sysButtons[1].anchor = { right = 2+(BUTTON_SIZE+3) + border, top = top + BUTTON_OFFSET };
+            sysButtons[1].size = { BUTTON_SIZE, BUTTON_SIZE };
             sysButtons[1].bevel = true;
             sysButtons[1].bitmap = { skinBitmaps[(state == maximized) ? restore : maximize] };
             sysButtons[1].visible = true;
@@ -544,7 +585,7 @@ public class WindowsSkin_Window : Window
          if(sysButtons[2])
          {
             sysButtons[2].anchor = { right = 2 + border, top = top + BUTTON_OFFSET };
-            sysButtons[2].size = { 15, 15 };
+            sysButtons[2].size = { BUTTON_SIZE, BUTTON_SIZE };
             sysButtons[2].bevel = true;
             sysButtons[2].bitmap = { skinBitmaps[close] };
             sysButtons[2].visible = true;
@@ -554,7 +595,7 @@ public class WindowsSkin_Window : Window
 }
 
 
-#define PUREVTBL(c)     ((int (**)())*(void **)((byte *)class(c).data + 4))
+#define PUREVTBL(c)     (*(void ***)((byte *)class(c).data + sizeof(uintptr)))
 #define CAPTION_DISTANCE   18
 
 default:
@@ -575,7 +616,7 @@ public class WindowsSkin_Button : Button
    {
       if(isRadio)
       {
-         PUREVTBL(Button)[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw](this, surface);
+         ((void (*)(Window, Surface))PUREVTBL(Button)[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw])(this, surface);
          return;
       }
       // if(bevel)
@@ -587,17 +628,28 @@ public class WindowsSkin_Button : Button
          Color backColor = background;
          int isDefault = this.isDefault;
          Font font;
+         int tw = 0, th = 0;
+         int bw = 0, bh = 0;
 
          font = fontObject;
+         surface.TextFont(font);
+         if(text)
+            surface.TextExtent(text, strlen(text),&tw, &th);
 
          if(bevelOver && checked)
             offset = 1;
 
          if(!isEnabled)
+         {
+            if(bitmaps[disabled]) buttonBitmap = bitmaps[disabled].bitmap;
             state = disabled;
+         }
+
+         if(buttonBitmap && buttonStyle.bevelOver && !buttonStyle.checkBox && !buttonStyle.radio && text)
+            isDefault = 0;
 
          // Background
-         if((bevel || bevelOver) && opacity && backColor)
+         if((bevel /*|| bevelOver*/) && opacity && backColor)
          {
             if(!scaleBitmap || !buttonBitmap)
             {
@@ -613,12 +665,12 @@ public class WindowsSkin_Button : Button
             int start = (clientSize.h - height) / 2;
 
             if(!isEnabled)
-               // surface.SetBackground(activeBorder);
+               // surface.SetBackground(formColor);
                surface.SetBackground(gainsboro);
             else if(active && !text)
-               surface.SetBackground((offset ? activeBorder : Color { 0,0,170 }));
+               surface.SetBackground((offset ? formColor : Color { 0,0,170 }));
             else
-               surface.SetBackground((offset ? activeBorder : white));
+               surface.SetBackground((offset ? formColor : white));
             surface.Area(2, start+2,height-3,start+height-3);
 
             surface.SetForeground(Color { 85, 85, 85 });
@@ -687,16 +739,37 @@ public class WindowsSkin_Button : Button
                }
                else
                {
-                  if(bevel || offset)
-                     surface.Blit(buttonBitmap,
-                        (clientSize.w-buttonBitmap.width) /2 + offset,
-                        (clientSize.h-buttonBitmap.height)/2 + offset,
-                        0,0,buttonBitmap.width,buttonBitmap.height);
+                  int x, y;
+                  bw = buttonBitmap.width;
+                  bh = buttonBitmap.height;
+
+                  if(bitmapAlignment == left || bitmapAlignment == right)
+                  {
+                     if(bitmapAlignment == left)
+                        x = 2;
+                     else
+                        x = clientSize.w-bw-2;
+                     y = (clientSize.h-bh)/2;
+                  }
+                  else if(bitmapAlignment == top || bitmapAlignment == bottom)
+                  {
+                     x = (clientSize.w-bw)/2;
+                     if(bitmapAlignment == top)
+                        y = 2;
+                     else
+                        y = clientSize.h-bh-2;
+                  }
                   else
-                     surface.Blit(buttonBitmap,
-                        (clientSize.w-buttonBitmap.width)/2,
-                        (clientSize.h-buttonBitmap.height)/2,
-                        0,0,buttonBitmap.width,buttonBitmap.height);
+                  {
+                     x = (clientSize.w-bw)/2;
+                     y = (clientSize.h-bh - (int)(buttonStyle.bevelOver && text) * th)/2;
+                  }
+                  if(buttonStyle.bevel || buttonStyle.offset)
+                  {
+                     x += offset;
+                     y += offset;
+                  }
+                  surface.Blit(buttonBitmap, x,y, 0,0, bw,bh);
                }
             }
          }
@@ -733,7 +806,6 @@ public class WindowsSkin_Button : Button
 
          // Text
          surface.TextOpacity(false);
-         surface.TextFont(font);
          surface.SetForeground(foreground);
          if(text)
          {
@@ -747,6 +819,18 @@ public class WindowsSkin_Button : Button
             {
                int x, y = (clientSize.h - th - 1)/2 + offset;
                
+               if(buttonStyle.bevelOver && buttonBitmap && !buttonStyle.checkBox && !buttonStyle.radio)
+               {
+                  if(bitmapAlignment == top)
+                     y = (clientSize.h - bh - 4 - th - 5)/2 + offset + bh + 4;
+                  else if(bitmapAlignment == bottom)
+                     y = (clientSize.h - bh - 4 - th - 5)/2 + offset;
+                  else//if(bitmapAlignment == left || bitmapAlignment == right)
+                     y = clientSize.h - th - 5 + offset;
+               }
+               else
+                  y = (clientSize.h - th - 1)/2 + offset;
+
                if(ellipsis)
                {
                   int width = clientSize.w - 2*6;
@@ -758,7 +842,13 @@ public class WindowsSkin_Button : Button
                {
                   int width = clientSize.w - 2 * 6;
                   x = 6 + offset;
-                  if(isCheckbox || ((isRadio || bevelOver) && buttonBitmap))
+                  if(bitmapAlignment == left || bitmapAlignment == right)
+                  {
+                     if(bitmapAlignment == left)
+                        x += bw + 4;
+                     width -= bw + 4;
+                  }
+                  if(isCheckbox || ((isRadio /*|| bevelOver*/) && buttonBitmap))
                   {
                      x += CAPTION_DISTANCE + 3;
                   }