Browse Source

X11TK: Flip the positioning of the UI if the locale is RTL (#14183)

eafton 2 days ago
parent
commit
2c0094ead6
3 changed files with 165 additions and 10 deletions
  1. 114 2
      src/video/x11/SDL_x11messagebox.c
  2. 41 0
      src/video/x11/SDL_x11toolkit.c
  3. 10 8
      src/video/x11/SDL_x11toolkit.h

+ 114 - 2
src/video/x11/SDL_x11messagebox.c

@@ -96,7 +96,7 @@ static void X11_PositionMessageBox(SDL_MessageBoxControlsX11 *controls, int *wp,
         controls->message->rect.y = X11Toolkit_GetIconControlCharY(controls->icon);
     } else {
         controls->message->rect.x = 0;
-        controls->message->rect.y = -2;
+        controls->message->rect.y = -2  * controls->window->iscale;
         controls->icon = &controls->fake_icon;
         controls->icon->rect.w = 0;
         controls->icon->rect.h = 0;
@@ -168,6 +168,114 @@ static void X11_PositionMessageBox(SDL_MessageBoxControlsX11 *controls, int *wp,
     *hp = h;
 }
 
+static void X11_PositionMessageBoxFlipped(SDL_MessageBoxControlsX11 *controls, int *wp, int *hp)
+{
+    int max_button_w;
+    int max_button_h;
+    int total_button_w;
+    int total_text_and_icon_w;
+    int w;
+    int h;
+    int i;
+    int t;
+
+    /* Init vars */
+    max_button_w = 50;
+    max_button_h = 0;
+    w = h = 2;
+    i = t = total_button_w = total_text_and_icon_w = 0;
+    max_button_w *= controls->window->iscale;
+
+    /* Positioning and sizing */
+    for (i = 0; i < controls->messageboxdata->numbuttons; i++) {
+        max_button_w = SDL_max(max_button_w, controls->buttons[i]->rect.w);
+        max_button_h = SDL_max(max_button_h, controls->buttons[i]->rect.h);
+        controls->buttons[i]->rect.x = 0;
+    }
+
+    if (controls->icon) {
+        controls->icon->rect.y = 0;
+    }
+
+    if (controls->icon) {
+        controls->message->rect.x = 0;
+        controls->message->rect.y = X11Toolkit_GetIconControlCharY(controls->icon);
+        controls->icon->rect.x = (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale) + controls->message->rect.w + controls->message->rect.x;
+   } else {
+        controls->message->rect.x = 0;
+        controls->message->rect.y = -2  * controls->window->iscale;
+        controls->icon = &controls->fake_icon;
+        controls->icon->rect.w = 0;
+        controls->icon->rect.h = 0;
+        controls->icon->rect.x = 0;
+        controls->icon->rect.y = 0;
+    }
+    if (controls->messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT) {
+        for (i = controls->messageboxdata->numbuttons; i != -1; i--) {
+            controls->buttons[i]->rect.w = max_button_w;
+            controls->buttons[i]->rect.h = max_button_h;
+            X11Toolkit_NotifyControlOfSizeChange(controls->buttons[i]);
+
+            if (controls->icon->rect.h > controls->message->rect.h) {
+                controls->buttons[i]->rect.y = controls->icon->rect.h + (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 *controls-> window->iscale);
+            } else {
+                controls->buttons[i]->rect.y = controls->message->rect.h + (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale);
+            }
+
+            if (i) {
+                controls->buttons[i]->rect.x = controls->buttons[i-1]->rect.x + controls->buttons[i-1]->rect.w + (SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * controls->window->iscale);
+            }
+        }
+    } else {
+        for (i = 0; i < controls->messageboxdata->numbuttons; i++) {
+            controls->buttons[i]->rect.w = max_button_w;
+            controls->buttons[i]->rect.h = max_button_h;
+            X11Toolkit_NotifyControlOfSizeChange(controls->buttons[i]);
+
+            if (controls->icon->rect.h > controls->message->rect.h) {
+                controls->buttons[i]->rect.y = controls->icon->rect.h + (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale);
+            } else {
+                controls->buttons[i]->rect.y = controls->message->rect.h + (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale);
+            }
+
+            if (i) {
+                controls->buttons[i]->rect.x = controls->buttons[i-1]->rect.x + controls->buttons[i-1]->rect.w + (SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * controls->window->iscale);
+            }
+        }
+    }
+    total_button_w = controls->buttons[controls->messageboxdata->numbuttons-1]->rect.x + controls->buttons[controls->messageboxdata->numbuttons-1]->rect.w;
+    total_text_and_icon_w =  controls->message->rect.w + controls->icon->rect.w + (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale);
+    if (total_button_w > total_text_and_icon_w) {
+        w = total_button_w;
+    } else {
+        w = total_text_and_icon_w;
+    }
+    w += (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale) * 2;
+    if (controls->message->rect.h > controls->icon->rect.h) {
+        h = controls->message->rect.h;
+    } else {
+        h = controls->icon->rect.h;
+    }
+    h += max_button_h + (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale) * 3;
+    t = (w - total_text_and_icon_w) / 2;
+    controls->icon->rect.x += t;
+    controls->message->rect.x += t;
+    controls->icon->rect.y += (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale);
+    controls->message->rect.y += (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale);
+    t = (w - total_button_w) / 2;
+    for (i = 0; i < controls->messageboxdata->numbuttons; i++) {
+        controls->buttons[i]->rect.x += t;
+        controls->buttons[i]->rect.y += (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale);
+    }
+    if (!controls->messageboxdata->message) {
+        controls->icon->rect.x = (w - controls->icon->rect.w)/2;
+    }
+
+    *wp = w;
+    *hp = h;
+}
+
+
 static void X11_OnMessageBoxScaleChange(SDL_ToolkitWindowX11 *window, void *data) {
     SDL_MessageBoxControlsX11 *controls;
     int w;
@@ -220,7 +328,11 @@ static bool X11_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int
     }
 
     /* Positioning */
-    X11_PositionMessageBox(&controls, &w, &h);
+    if (data.window->flip_interface) {
+        X11_PositionMessageBoxFlipped(&controls, &w, &h);
+    } else {
+        X11_PositionMessageBox(&controls, &w, &h);
+    }
 
     /* Actually create window, do event loop, cleanup */
     X11Toolkit_CreateWindowRes(controls.window, w, h, 0, 0, (char *)messageboxdata->title);

+ 41 - 0
src/video/x11/SDL_x11toolkit.c

@@ -603,6 +603,42 @@ static void X11Toolkit_GetTextWidthHeight(SDL_ToolkitWindowX11 *data, const char
     }
 }
 
+static bool X11Toolkit_ShouldFlipUI(void) 
+{
+    SDL_Locale **current_locales;
+    static const SDL_Locale rtl_locales[] = {
+        { "ar", NULL, },
+        { "fa", "AF", },
+        { "fa", "IR", },
+        { "he", NULL, },
+        { "iw", NULL, },
+        { "yi", NULL, },
+        { "ur", NULL, },
+        { "ug", NULL, },
+        { "kd", NULL, },
+        { "pk", "PK", },
+        { "ps", NULL, }
+    }; 
+    int current_locales_sz;
+    int i;
+
+    current_locales = SDL_GetPreferredLocales(&current_locales_sz);
+    if (current_locales_sz <= 0) {
+        return false;        
+    }
+    for (i = 0; i < SDL_arraysize(rtl_locales); ++i) {
+        if (SDL_startswith(current_locales[0]->language, rtl_locales[i].language)) {
+            if (!rtl_locales[i].country) {
+                return true;
+            } else {
+                return SDL_startswith(current_locales[0]->country, rtl_locales[i].country);
+            }
+        }
+    }
+    
+    return false;
+}
+
 SDL_ToolkitWindowX11 *X11Toolkit_CreateWindowStruct(SDL_Window *parent, SDL_ToolkitWindowX11 *tkparent, SDL_ToolkitWindowModeX11 mode, const SDL_MessageBoxColor *colorhints, bool create_new_display)
 {
     SDL_ToolkitWindowX11 *window;
@@ -809,9 +845,14 @@ SDL_ToolkitWindowX11 *X11Toolkit_CreateWindowStruct(SDL_Window *parent, SDL_Tool
     /* Menu windows */
     window->popup_windows = NULL;
 
+    /* BIDI engine */
 #ifdef HAVE_FRIBIDI_H
     window->fribidi = SDL_FriBidi_Create();
 #endif
+
+    /* Interface direction */
+    window->flip_interface = X11Toolkit_ShouldFlipUI();
+    
     return window;
 }
 

+ 10 - 8
src/video/x11/SDL_x11toolkit.h

@@ -72,9 +72,9 @@ typedef struct SDL_ToolkitWindowX11
     Window window;
     Drawable drawable;
 #ifndef NO_SHARED_MEMORY
-	XImage *image;
-	XShmSegmentInfo shm_info;
-	int shm_bytes_per_line;
+    XImage *image;
+    XShmSegmentInfo shm_info;
+    int shm_bytes_per_line;
 #endif
 
     /* Visuals and drawing */
@@ -94,8 +94,8 @@ typedef struct SDL_ToolkitWindowX11
     bool xrandr; // Whether Xrandr is present or not
 #endif
 #ifndef NO_SHARED_MEMORY
-	bool shm;
-	Bool shm_pixmap;
+    bool shm;
+    Bool shm_pixmap;
 #endif
     bool utf8;
     /* Atoms */
@@ -160,9 +160,11 @@ typedef struct SDL_ToolkitWindowX11
 
 #ifdef HAVE_FRIBIDI_H
     /* BIDI engine */
-	SDL_FriBidi *fribidi;
-	bool do_shaping;
+    SDL_FriBidi *fribidi;
+    bool do_shaping;
 #endif
+
+    bool flip_interface;
 } SDL_ToolkitWindowX11;
 
 typedef enum SDL_ToolkitControlStateX11
@@ -183,7 +185,7 @@ typedef struct SDL_ToolkitControlX11
     bool dynamic;
     bool is_default_enter;
     bool is_default_esc;
-	bool do_size;
+    bool do_size;
 
     /* User data */
     void *data;