An alternative MessageRequester [Windows]

Share your advanced PureBasic knowledge/code with the community.
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: An alternative MessageRequester [Windows]

Post by Zapman »

ShadowStorm wrote: Thu Feb 06, 2025 8:35 pmI would highly recommend a small addition that can be very useful, being able to copy selected text with a dedicated “Copy” menu, it can be useful sometimes to copy just part of the text.
Hi ShadowStorm, Thanks for testing.
The CTRL + C combination works as usually to copy a portion of text. Of course, a menu could make it more explicit for users who don't think to do it that way, but it would also make the interface cluttered, so I'm not convinced.
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: An alternative MessageRequester [Windows]

Post by Zapman »

ChrisR wrote: Fri Feb 07, 2025 1:07 am Seeing tx$ = "blabla" and all the tx$ + "blablabla" in the demo example, no real impact here but just to let you know, it is really much faster to write it all at once (with + to continue on the next line), it avoids searching for the end of the string each time.
You're absolutely right, ChrisR.
This is probably a sign that I'm a bit too old a programmer. I've kept some habits from the old days when PureBasic didn't allow strings to be split this way.
I'll auto-update, I promise.
Thanks for testing.
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: An alternative MessageRequester [Windows]

Post by Zapman »

AZJIO wrote: Fri Feb 07, 2025 1:27 amI am not a supporter for the texts to be stored in the executable file. We have 193 countries and a lot of languages. If you use 20 languages, then in any case we ignore the other many languages. Make the best option in one language, and connect the rest of the languages ​​using external files.
There is no doubt that your principle is the right one, Azjio. But here we are in a particular case of a library which must remain autonomous to be easily shareable on a forum. In most cases, this library will be used by programmers who only need a single language and can easily generate the corresponding texts from the examples provided in the code, if they are not already included.

It is rare for a programmer to need to develop an application that works in more than two or three languages, and even when that happens, they rarely aim to cover the entire world.
ChrisR wrote: Fri Feb 07, 2025 2:16 am I agree, and that's where the limit is for the alternative messageRequester, we can't compete with Microsoft's MUI translations.
Of course. But if the application that uses this library is multilingual, it will not find all of the texts it needs in Microsoft's MUI translations. It will have to, one way or another, manage a translation system.

Let's consider that case! I did so when I developed PBBrowser, which is currently available in four languages and includes and uses the Alert.pbi library we are discussing here.

The texts in Alert.pbi were obviously not the only ones that needed to be available in multiple languages for PBBrowser.
So, as you mentioned, Azjio, these various texts had to be centralized in an external file.
PBBrowser therefore defines another version of the GetTextFromCatalog procedure, which is responsible for retrieving texts from a file. That is why, in this library, this main procedure is enclosed within:

Code: Select all

CompilerIf Not Defined(GetTextFromCatalog, #PB_Procedure)
...
CompilerEndIf
This allows the user to define it differently, before XIncludeFile "Alert.pbi", ensuring that GetTextFromCatalog fetches texts from a file instead of using the default translations included in the code.

In this way, I have tried to reconcile the different ways this library can be used, because I personally use it in ALL my projects. Some of these projects are strictly personal and I have no need for multilingual support. I then simply define the global variable MyLanguage$ in my own language and the default translation suits me very well. Other projects are multilingual and I then define a GetTextFromCatalog procedure which allows me to manage the texts in a separate file. Some projects are not multilingual at the start, but they become so later, and I only have to add a different GetTextFromCatalog procedure so that everything continues to work without having to modify the Alert.pbi library.

The comment at the beginning of the code tries to explain that:

Code: Select all

;- 1. Language settings
;
; All Zapman libraries are now designed to be integrated into multilingual applications.
; It is entirely possible to redefine the 'GetTextFromCatalog()' function in a file
; that precedes this one in your 'IncludedFile' list. This way, you can store the
; different translations of the texts used in your application's gadgets in a
; different manner.
; However, the functions in this section provide a simple (and portable) way to do it,
; and if your language is not included in the list of translated languages, only a few
; lines need to be added to address this omission (look at the end of this section).
Last edited by Zapman on Fri Feb 07, 2025 12:16 pm, edited 2 times in total.
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: An alternative MessageRequester [Windows]

Post by Zapman »

Here is the code for the GetTextFromCatalog() procedure used by PBBrowser. It is saved under the name 'GetTextFromCatalog.pbi' and this file is included in the main code BEFORE Alert.pbi. Then, this procedure code is used instead of the one figuring in Alert.pbi :

Code: Select all

;
; ****************************************************************************
;
;                              GetTextFromCatalog
;                              Zapman - Feb 2025
;
; This one-procedure library provides a method to search for a translation key
; in a file and return an expression matching that key.
;
; This file should be saved under the name "GetTextFromCatalog.pbi".
;
; ****************************************************************************
;
Procedure.s GetTextFromCatalog(SName$, FileName$ = "", DontPanic = 0)
  ;
  ; Get a text line from a '.catalog' language file. The name of this file can be specified
  ; in the 'FileName$' parameter. In this file, you'll store all the texts needed by the application
  ; in the following form:
  ;
  ; Introduction     = Introduction
  ; CopyAll          = Copy all
  ; Search           = Search
  ; Save             = Save
  ; SaveAs           = Save As...
  ; etc.
  ;
  ; The left part (before the '=' sign) is the expression key that allways remain the same regardless
  ; of the destination language. The right part (after '=') is the expression translated into the
  ; destination language. There is one file per language and you designate this file by changing the
  ; 'FileName$' parameter.
  ;
  ; If 'SName$' is an existing expression-key in the file 'FileName$', the procedure returns what has been found
  ; after the '=' sign.
  ;
  ; This Procedure attempts to handle several scenarios:
  ; 1- If the 'FileName$' parameter is empty, the procedure will use the last file name used in the previous call.
  ;    This avoids having to specify the file name on each call. You only need to do this once, on the first call,
  ;    or when the user decides to change the language of the application.
  ; 2- Into the file 'FileName$', instead of containing a translation, the right part after the '=' sign following
  ;    a translation-key can point to a .txt Or .rtf file as this:
  ;        Introduction     = file:Introduction.rtf
  ;    This allows to return a complete RTF file for some expression keys.
  ; 3- Instead of containing an expression key, the 'SName$' parameter can contain something like
  ;    'file:NameOfAfile.txt' or 'file:NameOfAfile.rtf'. In this case, the procedure will search for this file name
  ;    in the folder designated by 'FileName$'. This allows in particular to obtain a text in RTF format in cases
  ;    where this is necessary.
  ;
  ; If an expression-key is missing in the catalog, an error message is printed if the parameter 'DontPanic' is omitted
  ; or equal to zero. If 'DontPanic' is other than zero, the procedure simply returns "MissingMention".
  ;
  ;
  Static mCatalogContent$, mFileName$
  ;
  Protected fsize, noFile, CatalogContent$, FString$
  Protected pos, posf
  ;
  If FileName$ : mFileName$ = FileName$
  Else
    FileName$ = mFileName$
    CatalogContent$ = mCatalogContent$
  EndIf
  ;
  If FileSize(FileName$) < 2
    MessageRequester("Oops!", "GetTextFromCatalog(): Catalog FileName is wrong or 'Catalog' is missing!" + #CR$ + FileName$)
    ProcedureReturn "MissingFile"
  EndIf
  ;
  If Left(SName$, 5) = "file:"
    ; The SName$ parameter contains a file name.
    ;
    FileName$ = GetPathPart(FileName$) + Mid(SName$, 6)
    If ReadFile(0, FileName$)
      fsize = Lof(0)
      If fsize > 0
        FString$ = Space(fsize)
        ReadData(0, @FString$, fsize)
      EndIf
      CloseFile(0)
      ProcedureReturn FString$
    Else
      MessageRequester("Oops!", "GetTextFromCatalog(): Unable to read the file!" + #CR$ + FileName$)
      ProcedureReturn SName$
    EndIf
  Else
    ;  The SName$ parameter contains a string name.
    ;
    If CatalogContent$ = ""
      noFile = ReadFile(#PB_Any, FileName$, #PB_File_SharedRead | #PB_File_SharedWrite)
      If noFile
        While Eof(noFile) = 0
          CatalogContent$ + ReadString(noFile, #PB_UTF8) + #CR$
        Wend
        CloseFile(noFile)
        CatalogContent$ = ReplaceString(CatalogContent$, #TAB$, " ")
        mCatalogContent$ = CatalogContent$
      Else
        MessageRequester("Oops!", "GetTextFromCatalog(): ReadingError while reading Catalog for '" + SName$ + "'" + #CR$ + "File exists, but can't be open." + #CR$ + FileName$)
        ProcedureReturn SName$
      EndIf
    EndIf
    ;
    If SName$
      If CatalogContent$
        pos = FindString(CatalogContent$, #CR$ + SName$ + " ")
        If pos = 0
          pos = FindString(CatalogContent$, #CR$ + SName$ + "=")
        EndIf
        If pos = 0
          pos = FindString(CatalogContent$, #CR$ + SName$ + " ", 0, #PB_String_NoCase)
        EndIf
        If pos = 0
          pos = FindString(CatalogContent$, #CR$ + SName$ + "=", 0, #PB_String_NoCase)
        EndIf
        If pos = 0
          If DontPanic
            ProcedureReturn "MissingMention"
          Else
            MessageRequester("Oops!", "GetTextFromCatalog(): '" + SName$ + "' can't be found in catalog!" + #CR$ + FileName$)
          EndIf
          ProcedureReturn SName$
        Else
          pos = FindString(CatalogContent$, "=", pos) + 2
          posf = FindString(CatalogContent$, #CR$, pos)
          FString$ = Mid(CatalogContent$, pos, posf - pos)
          If Left(FString$, 5) = "file:"
            ; The catalog redirects us to a file name.
            ;
            FileName$ = GetPathPart(FileName$) + Trim(Mid(FString$, 6))
            If ReadFile(0, FileName$)
              fsize = Lof(0)
              If fsize > 0
                FString$ = Space(fsize)
                ReadData(0, @FString$, fsize)
              EndIf
              CloseFile(0)
            Else
              MessageRequester("Oops!", "GetTextFromCatalog(): Unable to read the file!" + #CR$ + FileName$)
              ProcedureReturn SName$
            EndIf
          Else
            FString$ = ReplaceString(FString$, "%newline%", #CR$)
            FString$ = ReplaceString(FString$, "%quote%", #DOUBLEQUOTE$)
            FString$ = ReplaceString(FString$, "%equal%", "=")
            FString$ = ReplaceString(FString$, "%nonbreakingspace%", Chr(160))
            FString$ = ReplaceString(FString$, "£µ|", "%")
          EndIf
          ProcedureReturn FString$
        EndIf
      Else
        MessageRequester("Oops!", "Catalog is empty!")
        ProcedureReturn SName$
      EndIf
    Else
      ProcedureReturn SName$
    EndIf
  EndIf
EndProcedure
;
And here is a snippet of the PBBrowser.catalog for french:

Code: Select all

;
; PB Browser Language File
;

[LanguageInfo]
Application = PBBrowser
Language    = Francais
Creator     = Zapman Softwares - CatalogMaker
Email       = luc.deborde@gmail.com


[Common]

Introduction     = Présentation
CopyAll          = Tout copier
Search	         = Chercher
Save             = Enregistrer
SaveAs           = Enregistrer sous...
TextFile         = Fichiers Textes|*.txt
RTFFile          = Fichiers RTF|*.rtf
Cancel           = Annuler
Attention        = Attention
OK               = OK
Yes              = Oui
No               = Non
AlwaysOnTop      = Toujours devant
Change           = Changer
Open             = Ouvrir
Choose           = Choisir
About            = Aide et Outils
Quit             = Quitter

etc......
User avatar
skywalk
Addict
Addict
Posts: 4210
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: An alternative MessageRequester [Windows]

Post by skywalk »

When stepping through debugger it is an infinite loop.
I have 3 monitors so maybe your window is off screen?
I will get the lines that loop later today.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: An alternative MessageRequester [Windows]

Post by Zapman »

skywalk wrote: Fri Feb 07, 2025 2:45 pmI have 3 monitors so maybe your window is off screen?
I will get the lines that loop later today.
I'm more en more intrigued and interrested. Please tell me what happens exactly.
User avatar
skywalk
Addict
Addict
Posts: 4210
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: An alternative MessageRequester [Windows]

Post by skywalk »

Both Ex 4 and 6 have infinite loops:

Code: Select all

  CompilerCase 4;BUG
  tx$ = "This example shows how the 'Alert()' function window is able to automatically resize itself so that it can display "
  tx$ + "text of any length without the need to rewrite code each time you need to display a message of particular length." + #CR$
  tx$ + "There is no limit to the size of the message you can include here." + #CR$
  tx$ + "The size of the window will be increased as much as possible, then a scrollbar will appear to the right of the text box,"
  tx$ + " if the message is too large to fit entirely in the window."
  tx$ + #CR$ + tx$ + #CR$ + tx$ + #CR$ + tx$ + #CR$ + tx$ + #CR$ + tx$ + #CR$ + tx$ + #CR$
  tx$ + #CR$ + tx$ + #CR$ + tx$ + #CR$ + tx$ + #CR$ + tx$ + #CR$ + tx$ + #CR$ + tx$ + #CR$
  tx$ = "When the printed text is really large, a “search” button automatically appears to allow a search within the text."   + #CR$ + #CR$ + #CR$ + #CR$ + tx$
  Alert(tx$)

Code: Select all

  CompilerCase 6;BUG
  tx$ = "A variant of the Alert() function, named AlertYesNoCancel() is intended to replace MessageRequester() with the parameters #PB_MessageRequester_YesNo or #PB_MessageRequester_YesNoCancel." + #CR$
  tx$ + "It offers exactly the same flexibility As the 'Alert()' function."
  tx$ + #CR$ + #CR$ + "Possible parameters for this variant are:" + #CR$
  tx$ + "  #AW_AlertOnly" + #CR$
  tx$ + "  #AW_YesOrNo_YesByDefault" + #CR$
  tx$ + "  #AW_YesOrNo_NoByDefault" + #CR$
  tx$ + "  #AW_OKOrCancel_OKByDefault" + #CR$
  tx$ + "  #AW_OKOrCancel_CancelByDefault" + #CR$
  tx$ + "  #AW_YesNoOrCancel_YesByDefault" + #CR$
  tx$ + "  #AW_YesNoOrCancel_NoByDefault" + #CR$
  tx$ + "  #AW_YesNoOrCancel_CancelByDefault" + #CR$ + #CR$
  tx$ + "Here is an exemple of result with #AW_YesNoOrCancel_CancelByDefault" + #CR$ + #CR$
  tx$ + "The return values are the same as those of the MessageRequester function." + #CR$
  AlertYesNoCancel(tx$, "Demonstration", #AW_YesNoOrCancel_CancelByDefault)
Infinite loop here:

Code: Select all

    If ParentWindow = -1
      ParentWindow = EventWindow() ;<-- Looping here
    EndIf
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: An alternative MessageRequester [Windows]

Post by Zapman »

skywalk wrote: Fri Feb 07, 2025 4:44 pm Infinite loop here:

Code: Select all

    If ParentWindow = -1
      ParentWindow = EventWindow() ;<-- Looping here
    EndIf
Hi Skywalk,
Many thanks to give me some details.
Your case seems absolutely particular and I am trying to understand how PureBasic can block on a function such as EventWindow() (which is normally impossible).
I have just updated the code (still available in the first post of this message) and I would be very grateful if you could test with this version and tell me if it solves the problem.
User avatar
skywalk
Addict
Addict
Posts: 4210
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: An alternative MessageRequester [Windows]

Post by skywalk »

Yayyy, you fixed the hang. :D
Now just a question of window/alert placement for multiple screen use?
If user does not enable compiler option = DPI, then your examples are all top left window positioned at lower right of 1st display. With DPI enabled, alert window is centered on display 1.

Code: Select all

++++++++++++++++
+              +
+      3       +
+              +
++++++++++++++++
++++++++++++++++
+              +
+      2       +
+              +
++++++++++++++++
++++++++++++++++
+              +
+      1       +
+         alert+
++++++++++++++++
I put this at the top of my main files for app specific settings:

Code: Select all

; =================================================
; COMPILER OPTIONS:
;   [ ] Main source file:
;   [x] Use Compiler:   PureBasic 6.20 Beta 4 (Windows - x64)
;                       PureBasic 6.20 Beta 4 - C Backend (Windows - x64)
;   [x] Use Icon:       C:\?
;   [x] Optimize generated code
;   [ ] Enable inline ASM syntax coloring
;   [x] Create threadsafe executable
;   [ ] Enable OnError lines support
;   [x] Enable DPI aware executable (Windows and macOS)
;   [x] Enable modern theme support (Windows XP and above)
;   [ ] Request Administrator mode for Windows Vista and above
;   [ ] Request User mode for Windows Vista (no virtualisation)
;   [ ] Enable DLL preloading protection (Windows)
;   [x] Use share UCRT (Windows 10 and above)
;   [ ] Enable Wayland support
;   Library Subsystem:
;   Executable format:        Windows ;|Console|Shared DLL
;                             All CPU ;|Dynamic|w/MMX|w/3DNOW|w/SSE|w/SSE2
;   Linker options file:      
; COMPILE/RUN:
;   Debugger:
;     [x] Enable Debugger
;     [x] Enable Purifier
;     [ ] Use selected Debugger:      ;Integrated IDE Debugger
;     [ ] Use Warning mode:           ;Display Warnings
;   Run executable with:
;     Executable Commandline:         ;
;     Current directory:              ;C:\dev\
;     [x] Create temporary executable in the source directory
; CONSTANTS:
; VERSION INFO:
;   [x] Include Version Information
;   Update version info in:   auto set fields --> %yy.%mm.%dd
; RESOURCES:
;   C:\dev\some-resource.rc
; IDE PREFERENCES:
;   Compiler:Defaults:
;     Sourcefile Text encoding: UTF-8
;   ToolsPanel:Configuration:Procedure Browser
;     [x] Sort Procedures by name       ;<-- Alphabetical instead of order of appearance. Uncheck when location of Proc desired.
;     [ ] Group Markers                 ;<-- If checked, ';-!' priority listing is lost.
;     [ ] Display Procedure Arguments   ;<-- Too busy if checked.
;   Editor:
;     Save Settings to: The end of the Source file
;                       | The file <filename>.pb.cfg | A common file project.cfg for every directory | Don't save anything
;     Tab Length:       2 [ ] Use real Tab (ASCII 9)
;     Source Directory: c:\dev\
;   Debugger: 
;     Choose Debugger Type:  Integrated IDE Debugger ;|Standalone GUI Debugger|Console only Debugger
;     Choose Warning level:  Display Warnings
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: An alternative MessageRequester [Windows]

Post by Zapman »

skywalk wrote: Sat Feb 08, 2025 4:06 pmIf user does not enable compiler option = DPI, then your examples are all top left window positioned at lower right of 1st display. With DPI enabled, alert window is centered on display 1.
I shamefully admit that I hadn't considered that the DPI option could be disabled. :oops:
Thanks a lot for pointing this out.
I've updated the code in the first post of this message.
The Feb. 2025-4 version fixes the problem.

May the Force to be with you.

P.S. : Note that if a PB windows is open before the call to Alert(), the Alert's window will be centered relatively to the precedent one, no matter what screen it is on. (I hope it works that way for you anyway).
ShadowStorm
Enthusiast
Enthusiast
Posts: 303
Joined: Tue Feb 14, 2017 12:07 pm

Re: An alternative MessageRequester [Windows]

Post by ShadowStorm »

Zapman wrote: Fri Feb 07, 2025 9:41 am
ShadowStorm wrote: Thu Feb 06, 2025 8:35 pmI would highly recommend a small addition that can be very useful, being able to copy selected text with a dedicated “Copy” menu, it can be useful sometimes to copy just part of the text.
Hi ShadowStorm, Thanks for testing.
The CTRL + C combination works as usually to copy a portion of text. Of course, a menu could make it more explicit for users who don't think to do it that way, but it would also make the interface cluttered, so I'm not convinced.
Hello ZapMan,
Please, I insist on my request, it's useful you know :)
I am French, I do not speak English.
My apologies for the mistakes.

I have sometimes problems of expression
I am sometimes quite clumsy, please excuse me and let me know.
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: An alternative MessageRequester [Windows]

Post by Zapman »

The code has been updated (still available from the first post of this subject).

From a ShadowStorm's demand, the 'Copy' button now allows to copy only the selected text (the CTRL C is also usable).
From a ChrisR suggestion, the positioning of the window now offers many different options.
ShadowStorm
Enthusiast
Enthusiast
Posts: 303
Joined: Tue Feb 14, 2017 12:07 pm

Re: An alternative MessageRequester [Windows]

Post by ShadowStorm »

Thank you ^^
I am French, I do not speak English.
My apologies for the mistakes.

I have sometimes problems of expression
I am sometimes quite clumsy, please excuse me and let me know.
Post Reply