I have managed to replicate the PowerBasic dialog engine. Besides being able to use dialog units or pixels, you can also use your own class name. No more problem to use FindWindow because all PB dialogs use the "#32770" class.
' // Set process DPI aware
AfxSetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)
' // Enable visual styles without including a manifest file
AfxEnableVisualStyles
' // Create an instance of the Dialog class. The default font is Segoe UI, 9 points.
' // You can specify the font, size, style and charset, e.g. DIM pDlg AS CDialog = CDialog("Tahoma", 9).
DIM pDlg AS CDialog = CDialog("Segoe UI", 9)
DIM dwStyle AS LONG = WS_OVERLAPPEDWINDOW OR DS_MODALFRAME OR DS_CENTER
' // Create dialog using dialog units
DIM hDlg AS HWND = pDlg.DialogNew(0, "Dialog New",,, 440, 190, dwStyle)
' // Create custom dialog using dialog units
' DIM hDlg AS HWND = pDlg.DialogNew("MyClassName", 0, "Dialog New",,, 440, 190, dwStyle)
' // Create dialog using pixels
' DIM hDlg AS HWND = pDlg.DialogNewPixels(0, "Dialog New",,, 1344, 777, dwStyle)
' // Create custom dialog using pixels
' DIM hDlg AS HWND = pDlg.DialogNewPixels("MyClassName", 0, "Dialog New",,, 1344, 777, dwStyle)
Thanks to Pierre Bellisle for letting me know about the possibility of using visual styles without including a manifest file. Very useful for testing.
The option of using pixels does not work as it should. Using dialog units works perfectly, both using the predefined dialog class and a custom class.
Problem solved. When using pixels, resizing has to be done using the High DPI ratios, which are not the same as the dialog units to pixels ratios.
Now we have four possibilities: classic dialog (#32770), custom dialog (custom class), classic dialog using pixels, custom dialog using pixels.
Using CDialog with pixels works like CWindow. Therefore, I don't need to adapt CWindow.
The advantage of using dialog units is that the main window and the controls are resized changing the font. The disadvantage is that the ratios change, making it hard to work with the Windows standard controls that work with pixels.
I have fully replicated (and improved) the PowerBasic dialog engine. Like PB can work with classic dialogs (window class #32770), both using dialog units or pixels, and unlike PB it allows the creation and use of custom dialogs wirh the class name of your choice and it is DPI aware when workimg with pixels. Works with 32 and 64-bit without changing anything in the code.
I also have integrated optional anchoring of the controls for easy automatic resizing when the size of the dialog changes.
Code available in GitHub:
https://github.com/JoseRoca/WinFBX2
I'm writing now a procedural wrapper to allow the use of CDialog with a DDT-like syntax. Do you think that it is DDT-friendly enough? The main difference if that it will use functions instead of these outdated and horrible statements, i.e. instead of CONTROL GET TEXT hDlg, id& TO txt$, it will use txt = ControlGetText(hDlg, id).
#include once "Afx2/DDT.inc"
USING DDT
' // Forward declaration
DECLARE FUNCTION DlgProc (BYVAL hDlg AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
' // Button identifier
CONST IDC_BUTTON = 1001
' ******* PROGRAM START ******
' // Create a dialog using dialog units
' // It is equivalent to DIALOG NEW (the class name used is the standard #32770)
DIM dwStyle AS LONG = WS_OVERLAPPEDWINDOW OR DS_CENTER
DIM hDlg AS HWND = DialogNew(NULL, "Dialog New", 50, 50, 175, 75, dwStyle)
' // Add a button
' // It is equivalent to CONTROL ADD (can be used with any control)
ControlAdd "Button", hDlg, IDC_BUTTON, "&Click me", 95, 45, 50, 12
' // Anchor the button to the bottom and right sides of the dialog
' // The button will be repositioned automatically to the new width
' // and height of the dialog when you resize it.
' // This has not equivalence in DDT
ControlAnchor(hDlg, IDC_BUTTON, ANCHOR_BOTTOM_RIGHT)
' // Display and activate the dialog as modal
' // This is equivalent to DIALOG SHOW MODAL
DialogShowModal(hDlg, @DlgProc)
' ******* PROGRAM END ******
END
' ========================================================================================
' Main window procedure
' ========================================================================================
FUNCTION DlgProc (BYVAL hDlg AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
SELECT CASE uMsg
CASE WM_INITDIALOG
RETURN TRUE
CASE WM_COMMAND
SELECT CASE CBCTL(wParam, lParam)
CASE IDCANCEL
' // If ESC key pressed, close the application by sending an WM_CLOSE message
IF CBCTLMSG(wParam, lParam) = BN_CLICKED THEN
SendMessageW hDlg, WM_CLOSE, 0, 0
END IF
CASE IDC_BUTTON
IF CBCTLMSG(wParam, lParam) = BN_CLICKED THEN
MsgBox "Button pressed"
END IF
END SELECT
CASE WM_CLOSE
' // End the application
' // This is equivalent to DIALOG END
DialogEnd(hDlg)
END SELECT
RETURN FALSE
END FUNCTION
' ========================================================================================
BTW Paul Squires is finishing a new editor that will make the use of my framework and FreeBasic a breeze.
To subclass controls, it is much better to use the SetWindowSubclass API function that the outdated method used by DDT when you add CALL callback to CONTROL ADD. Things evolve and we and to keep up to date.
Quote from: José Roca on June 02, 2025, 03:24:32 PMBTW Paul Squires is finishing a new editor that will make the use of my framework and FreeBasic a breeze.
Means he also did not want to stay so long without work in pension and is back at the computer.
Did he reopen his Forum or where is he publishing?
Ok, i see he is using GitHub (Microsoft).
So if so I recommend to take a look here.
Openai Codex for Github.
https://chatgpt.com/codex/onboarding/connections (https://chatgpt.com/codex/onboarding/connections)
Imagin this will just scan your files and find hidden buugs, or make changes yo tell it to do.
Included is a lot of free API Access!
Yes, he has reopened his forum.
https://www.planetsquires.com/protect/forum/index.php
QuoteOpenai Codex for Github.
https://chatgpt.com/codex/onboarding/connections
Imagin this will just scan your files and find hidden buugs, or make changes yo tell it to do.
Included is a lot of free API Access!
I doubt it will be of any help. Maybe it will work well with C++ (there is a lot of code to steal), but with FreeBasic they don't produce valid code. I use Copilot sometimes, inestead of Goodle, to find some information.
Why you don't ask AI to write an user manual for O2?
I can tell you that its in its simple form unable to write any output larger then 60 kToken, in real mostly much less. Input with Google AI-Studio is up to 1024 MToken.
So you need to code a "large output engine"" first.
However you could code a KI-Coder-Browser easily. i saw a lot of people currently try to make browsers that can do things using calling an KI-API. I thought "Jose could do it better if he want".
You can use www.openrouter.ai free Models for testing, it will not cost anything, you just need to register and then your Browser could call the free Models that are available there and this way you could make a browser that can do many things automatically and it shoiuld contain an MCP Server so it can be used as Agent from Roocode, Cline, Cursor, Windsurf and all other KI's out there.
Such programs that can connecct to AI have a huge demand currently.
Actually there is so much demand for KI-Stuff that can be coded so easily (as KI can do most of the work for you).
Generally you an take any program "of the past" and connect it to KI using an MCP-Server or just give it an Interface to Openrouter so the user can just "say to the Texteditor" -> "Make me all functions use Register variables". And the editor will call the AI (As said there are many free AI's and also you can use Local AI's if you want privacy) - and the Editor will just do that.
Where AI currently struggles is the limited Input Context (Free AI mostly 128-56 KToken) especially the short Output-length (often 8 kToken or less).
However there are solutions and you can then alterantively use (paid) google API's they bring you 1MToken Inoput Kontext and up to 65KToken Output Kontext.
Have you ever thought of making a KI-driven version of the SED-Editor?
What could KI do in an Editor to make your life easier?
ANd remember - you can use free LI (for example using OpenRouter as Backend, also OpenAI gives you 10 MToken each Day free API Access) and if you want privacy, you can use LM-Studio and the KI will run on your private computer.
Good luck, i made a video on that:
Thats not a problem, because for example using Mistral.ai (you can define an freebasic agent yourself)
of using Google AI-Studio, you can just use a 1 MB Textfile with all of Freebasic's Syntax and then tell him what to do with it.
I can tell you "it works" because using this system it will even code SPR-Programs and the SPR code is far from any conventional syntax.
In fact you can design an own programming language, feed the definition into AI Studio, an the KI can immediately code with it. Give it a try.
Since he seems to have dropped all support even for his paid software there is not so much for me in there.
His Fireflyy visaul designer was a fine product - i still use it.
However it would definitely need some updates.
We have now the good old Powerbasic (which i use because all my code is in that and i know the syntax)
then we have Charles very interestig O2 - which i corporates some genius conceptsand we have the source code so we could even change it like we want if we need.
and now we have freebasic.
And all of these incompatible with each other and that is the main problem.
I'm programming for fun. If AI does the programming for me, where is the fun?
The Fun of Programming with AI: A Game-Changer for Coders!
The fun of programming has skyrocketed! Now, you're not just coding solo—you've got 1, 3, or even 4 AI assistants taking on the boring parts, helping you reach your goals 4 times faster!
It feels like the first time you discovered PowerBASIC—remember the thrill? You'd talk to the compiler, tweak inputs, and learn from error messages. Now, it's the same vibe, but the new "AI Compiler" is a dream—way smarter than the good old PowerBASIC days. It gives you much better answers and makes coding a breeze!
Here's why coding with AI is more fun and a total game-changer:
Build 4x Larger Projects
Tackle massive projects with ease, thanks to AI handling repetitive tasks.
No More Chasing Boring Errors
Forget sweating over typos or silly bugs—AI (like Grok or others) will spot them for you!
Feel Like a Team of Coders
Work as if you have a whole crew by your side, boosting your productivity.
Make Your Programs Smarter
Integrate AI to create intuitive apps that even "less tech-savvy" users can understand.
Speed Things Up with AI-Generated ASM Code
Let AI whip up assembly code for those performance-critical sections.
Become Besties with AI
Over time, you'll get the hang of "how AI ticks" and start treating it like a trusted friend. That's how it feels for me, at least!
Code in Languages You Don't Even Know
Okay, MASTER. Thank you for providing the specific documentation for GSB. / JSR..
You are correct. The documentation clearly shows that GSB.Label|Param1|Param2... is the standard way to pass parameters, and they are accessed within the subroutine using §§_01, §§_02, etc. My previous modification to use the stack (PNS/GSB/POP) for all calls was an incorrect generalization based on only some examples.
Based on this corrected understanding:
Part 2 requires revision: I need to revert the changes where I replaced GSB.Label|Param with PNS/GSB/POP. The original direct parameter passing was correct.
Part 3 (:Run) requires revision: The :Run subroutine should access its input command string using VAR.$$CMD=§§_01 instead of POV.$$CMD. Internal GSB calls within :Run should also use direct parameter passing.
Parts 4 and 5: The subroutines themselves need to be adjusted to expect parameters via §§_xx instead of using POV (unless POV was explicitly intended for stack manipulation in a specific subroutine like :DoJsonEscape).
Action Plan:
I will first revise Part 2 according to this corrected understanding of GSB. parameter passing.
I will present the revised Part 2 for your approval.
Once Part 2 is approved, I will proceed with revising Part 3 (:Run) based on this new understanding.
Let me provide the corrected Part 2 now.
Corrected Part 2 (Revision 2 - GSB Parameter Handling)
Generated spr
'=======================================================================
' --- Main Execution Loop ---
'=======================================================================
:Main_Loop
' --- Increment Loop Counter & Check Limit ---
VIC.$$LPC
IVV.$$LPC>$$MAX
PRT.ERROR MainLoop - Maximum iterations ($$MAX) reached.
GTO.Exit
EIF.
' --- Loop Detection ---
VAR.$$CMH=$$CMD
VAR.$$DOL=0
IVS.$$CMH=$$HI1
IVS.$$CMH=$$HI2
IVS.$$CMH=$$HI3
IVS.$$CMH=$$HI4
PRT.WARNING MainLoop - LOOP DETECTED: Command '$$CMH' repeated 4 times. Intervening.
VAR.$$DOL=1
EIF.
EIF.
EIF.
EIF.
' --- Intervention Logic (If Loop Detected) ---
IVV.$$DOL=1
GSB.ParseCmd|$$CMH
POP.$$ACT|$$AGN|$$DTL|$$MOD
SCS.$$ACT
CAS.RUN
VAR.$$CMD=GET_CONCEPT
PRT.INFO MainLoop - Intervention: Forcing GET_CONCEPT.
CAS.LIST_AGENTS
VAR.$$CMD=GET_CONCEPT
PRT.INFO MainLoop - Intervention: Forcing GET_CONCEPT.
CAS.READ_FILE
VAR.$$CMD=CLEAR_CONTEXT.ALL
PRT.INFO MainLoop - Intervention: Forcing CLEAR_CONTEXT.ALL.
CAS.READ_FILE_TAIL
VAR.$$CMD=CLEAR_CONTEXT.ALL
PRT.INFO MainLoop - Intervention: Forcing CLEAR_CONTEXT.ALL.
CAS.GET_CONCEPT
VAR.$$CMD=CLEAR_CONTEXT.ALL
PRT.INFO MainLoop - Intervention: Forcing CLEAR_CONTEXT.ALL.
CAS.GET_PLAN
VAR.$$CMD=CLEAR_CONTEXT.ALL
PRT.INFO MainLoop - Intervention: Forcing CLEAR_CONTEXT.ALL.
CAE.
VAR.$$CMD=EXIT_WORKFLOW.Loop detected for unknown/other command '$$ACT'.
PRT.ERROR MainLoop - Intervention: Forcing EXIT due to loop on '$$ACT'.
ESC.
' --- Reset History after intervention ---
VAR.$$HI1=
VAR.$$HI2=
VAR.$$HI3=
VAR.$$HI4=
PRT.DEBUG MainLoop - Command history reset. Next command is intervention: $$CMD
GTO.Main_Loop
EIF.
' --- Update Command History (if no loop detected) ---
VAR.$$HI4=$$HI3
VAR.$$HI3=$$HI2
VAR.$$HI2=$$HI1
VAR.$$HI1=$$CMH
' --- Process Current Command ---
PRT.INFO MainLoop - Loop $$LPC / $$MAX CMD: $$CMD
VAR.$$LRC=$$CMD
VBT.$$LRC
JNS.$$LRC|Main_Loop_Continue
' Command is empty, skip to next iteration
' --- Parse and Dispatch ---
VAR.$$ACT=
VAR.$$AGN=
VAR.$$DTL=
VAR.$$MOD=
GSB.ParseCmd|$$LRC
POP.$$ACT|$$AGN|$$DTL|$$MOD
JNS.$$ACT|Parse_Cmd_Failed
' Jump if Action is empty after parsing
' --- Main Command Dispatch ---
VAR.$$RES=1
' Default success assumption
VAR.$$NPM=
' Default Next PM message (empty)
VAR.$$LSA=
' Clear Last Source Agent before action
SCS.$$ACT
CAS.RUN
GSB.Run|$$LRC
POP.$$RES
' --- Post-RUN logic ---
IVV.$$RES=1
PRT.DEBUG MainLoop - RUN successful. Last source agent: $$LSA
VAR.$$TMP=$$LSA
VTU.$$TMP
IVS.$$TMP!PROJECT_MANAGER
' Non-PM agent ran successfully. Call PM with its output.
PRT.DEBUG MainLoop - Non-PM agent $$LSA ran. Preparing PM call.
VAR.$$TMP=$$LSA
VAR.$$TMP=$$TMP$: $$TEX
' Prefix output with agent name
' --- Truncate $$TMP if needed (Simple truncation) ---
LEN.$$TMP|$$LEN
IVV.$$LEN>1000
GSS.1|1000|$$TMP|$$TMP
VAR.$$TMP=$$TMP... (truncated)
EIF.
' Set NEXT command to inform PM
VAR.$$CMD=RUN.PROJECT_MANAGER.$$TMP.GM
PRT.DEBUG MainLoop - Set next CMD to call PM.
ELS.
' PROJECT_MANAGER itself ran successfully. Process its output.
PRT.DEBUG MainLoop - PM ran successfully. Processing its output $$TEX.
' Uses $$TEX, sets global $$CMD for next loop
GSB.DetermineNextCmdPM
' No params needed as it reads global $$TEX
EIF.
EIF.
' If $$RES=0, :Run already set $$CMD to PM error msg. Flow continues below.
CAS.HIRE
GSB.Hire|$$LRC
POP.$$RES
IVV.$$RES=1
VAR.$$NPM=INFO: Agent hired via '$$LRC'.
ELS.
VAR.$$NPM=ERROR: HIRE failed for '$$LRC'.
EIF.
CAS.LIST_AGENTS
GSB.List
' No params needed, no result popped
VAR.$$RES=1
VAR.$$NPM=INFO: Agent list displayed.
CAS.RETIRE
GSB.Retire|$$LRC
POP.$$RES
IVV.$$RES=1
VAR.$$NPM=INFO: Agent retired via '$$LRC'.
ELS.
VAR.$$NPM=ERROR: RETIRE failed for '$$LRC'.
EIF.
CAS.SAVE_AGENT_STATE
GSB.Sav_All
POP.$$RES
IVV.$$RES=1
VAR.$$NPM=INFO: Agent state saved.
ELS.
VAR.$$NPM=ERROR: SAVE_AGENT_STATE failed.
EIF.
CAS.CLEAR_AGENTS
GSB.Clear
POP.$$RES
IVV.$$RES=1
VAR.$$NPM=INFO: Agent state cleared.
ELS.
VAR.$$NPM=ERROR: CLEAR_AGENTS failed.
EIF.
' --- PM Directed Script Actions ---
CAS.READ_FILE
GSB.handle_read_file|$$LRC
POP.$$RES
CAS.READ_FILE_TAIL
GSB.handle_read_file_tail|$$LRC
POP.$$RES
CAS.GET_CONCEPT
GSB.handle_get_concept
POP.$$RES
CAS.GET_PLAN
GSB.handle_get_plan
POP.$$RES
CAS.CLEAR_CONTEXT
GSB.handle_clear_context|$$LRC
POP.$$RES
CAS.SAVE_CONTEXT
GSB.handle_save_context|$$LRC
POP.$$RES
CAS.EXIT_WORKFLOW
PRT.INFO MainLoop - EXIT_WORKFLOW command received. Reason: $$DTL
GTO.Exit
CAE.
PRT.ERROR MainLoop - Unknown ACTION received in dispatch: '$$ACT'. Command: $$LRC
VAR.$$RES=0
VAR.$$NPM=ERROR: Unknown action '$$ACT' received.
ESC.
' End Main Dispatch SCS
' --- Post-Action Processing (Determine next $$CMD if not already set) ---
IVV.$$RES=1
' Action Succeeded ($$RES=1)
PRT.DEBUG MainLoop - Action '$$ACT' completed successfully.
VAR.$$ERC=0
' Reset consecutive error count
VAR.$$AKY=$$ACT
VTU.$$AKY
IVS.$$AKY=RUN
' RUN logic already handled setting next $$CMD
ELS.
IVS.$$AKY=EXIT_WORKFLOW
' EXIT logic already handled via GTO
ELS.
' Action was NOT RUN/EXIT and succeeded. Check if handler set CMD.
VAR.$$CTM=$$CMD
IVS.$$CTM=$$LRC
' If CMD hasn't changed, the handler didn't set it. We need to call PM.
LEN.$$NPM|$$LEN
IVV.$$LEN>0
' $$NPM is NOT empty, use the specific status message
VAR.$$CMD=RUN.PROJECT_MANAGER.$$NPM.GM
PRT.DEBUG MainLoop - Has NPM. Set next CMD to inform PM: $$CMD
ELS.
' $$NPM IS empty, send generic INFO message
VAR.$$CMD=RUN.PROJECT_MANAGER.INFO: Action '$$ACT' completed OK.GM
PRT.DEBUG MainLoop - No NPM. Set generic PM success info CMD.
EIF.
ELS.
' Handler (like READ_FILE) already set $$CMD. Keep it.
PRT.DEBUG MainLoop - Handler for '$$ACT' already set next CMD: $$CMD
EIF.
EIF.
EIF.
ELS.
' Action Failed ($$RES=0)
VIC.$$ERC
PRT.ERROR MainLoop - Action '$$ACT' FAILED. Error count: $$ERC / $$ERR
' --- Refactored check for >= ---
IVV.$$ERC<$$ERR
' ERC is less than ERR, continue
ELS.
' ERC is greater than or equal to ERR, exit
PRT.FATAL MainLoop - Maximum consecutive errors ($$ERR) reached.
GTO.Exit_Error
EIF.
' Set next command to call PM with the Error message
LEN.$$NPM|$$LEN
IVV.$$LEN>0
' Check if a specific error message exists in $$NPM
VAR.$$CMD=RUN.PROJECT_MANAGER.$$NPM.GM
ELS.
' Use generic failure message if $$NPM empty
VAR.$$CMD=RUN.PROJECT_MANAGER.ERROR: Action '$$ACT' failed (from RES=0).GM
EIF.
PRT.DEBUG MainLoop - Set next CMD to report error to PM: $$CMD
EIF.
:Main_Loop_Continue
GTO.Main_Loop
:Parse_Cmd_Failed
PRT.ERROR MainLoop - Command parsing failed for: '$$LRC'. Defaulting to LIST_AGENTS.
VAR.$$CMD=LIST_AGENTS
GTO.Main_Loop_Continue
'=======================================================================
' --- Subroutines (BEGIN IN NEXT PART) ---
'=======================================================================
IGNORE_WHEN_COPYING_START
Use code with caution. Spr
IGNORE_WHEN_COPYING_END
Summary of Changes in Corrected Part 2 (Revision 2):
GSB Parameter Passing: Reverted all PNS/GSB/POP sequences back to the direct GSB.Label|Param1... format.
POP Usage: Retained POP only where a subroutine is documented or logically expected to return a value that needs to be captured immediately after the GSB call (e.g., after GSB.ParseCmd, GSB.Run, GSB.Hire, etc.). Subroutines like :List or :DetermineNextCmdPM which primarily modify globals or print output don't require a POP.
Other corrections from the previous review (inline comments, $len, JNS targets, IVV operators) are maintained.
Please review this corrected Part 2, MASTER. Let me know if this aligns with your intent before I proceed with revising Part 3 (:Run) according to the §§_xx parameter access method.
You really need help using that syntax :)
It's not a new invention. Back then, they called it mnemonics. The main difference now is that these mnemonics don't just include x86 or x64 instructions, but also cover program calls for more complex systems. The rest of the syntax has pretty much stayed the same as with the old assembler. 🖥�🔡🚀
On the other hand, I wanted to show that if AI can generate this kind of syntax, then it can certainly handle FreeBASIC as well. Don't you think?
The day before yesterday was June 20, 2025, a date worth remembering—it marks the day when American AI companies were definitively outperformed by their Chinese counterparts. One of these new Chinese AIs is the one you're interacting with right now. You should definitely give it a try.
And the code you see below is a one-shot. I simply asked the AI to create a magnifying glass in FreeBASIC, as I didn't have any other ideas at the moment. But doesn't the result look nothing like FreeBASIC?
#FreeBASIC #AIgeneratedCode #Programming #MagnifyingGlass #CodeReview
https://agent.minimax.io/share/282725486514240 (https://agent.minimax.io/chat?id=282717376176212)
#ArtificialIntelligence #AICoding #FreeBASIC #ProgrammingThoughts #AIDevelopment
' Magnifying Glass Tool - FreeBasic GUI Application
' Created by MiniMax Agent
' Features: Form with magnifying glass functionality
#include "fbgfx.bi"
#include "windows.bi"
' Constants for the application
Const SCREEN_WIDTH = 800
Const SCREEN_HEIGHT = 600
Const MAG_SIZE = 200 ' Size of magnifying glass circle
Const MAG_ZOOM = 3 ' Magnification factor
' Structure to hold magnifying glass state
Type MagnifyingGlass
x As Integer ' Current X position
y As Integer ' Current Y position
active As Integer ' Is magnifying glass active
radius As Integer ' Radius of magnifying glass
zoom As Single ' Zoom factor
End Type
' Global variables
Dim Shared mag As MagnifyingGlass
Dim Shared background_buffer As Any Ptr
Dim Shared mag_buffer As Any Ptr
' Initialize the magnifying glass
Sub InitMagnifyingGlass()
mag.x = SCREEN_WIDTH \ 2
mag.y = SCREEN_HEIGHT \ 2
mag.active = 0
mag.radius = MAG_SIZE \ 2
mag.zoom = MAG_ZOOM
' Create image buffers
background_buffer = ImageCreate(SCREEN_WIDTH, SCREEN_HEIGHT)
mag_buffer = ImageCreate(mag.radius * 2, mag.radius * 2)
End Sub
' Draw the background scene (sample content to magnify)
Sub DrawBackground()
' Clear screen with gradient background
For y As Integer = 0 To SCREEN_HEIGHT - 1
Dim col As UInteger = RGB(y \ 3, (y + 100) \ 4, 255 - y \ 3)
Line (0, y)-(SCREEN_WIDTH, y), col
Next
' Draw some sample objects to magnify
Circle (150, 150), 50, RGB(255, 255, 0)
Circle (150, 150), 30, RGB(255, 0, 0)
Circle (400, 300), 80, RGB(0, 255, 0)
Circle (400, 300), 60, RGB(0, 0, 255)
Circle (400, 300), 40, RGB(255, 255, 255)
' Draw some text
Draw String (50, 50), "Sample Text to Magnify", RGB(255, 255, 255)
Draw String (300, 100), "FreeBasic Magnifying Glass", RGB(255, 255, 0)
Draw String (200, 500), "Click to activate magnifying glass", RGB(200, 200, 200)
' Draw rectangles
Line (600, 200)-(700, 300), RGB(255, 0, 255), BF
Line (610, 210)-(690, 290), RGB(0, 255, 255), BF
' Save current screen to background buffer
Get (0, 0)-(SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1), background_buffer
End Sub
' Apply magnifying glass effect
Sub ApplyMagnifyingGlass(mx As Integer, my As Integer)
If background_buffer = 0 Then Exit Sub
' Calculate source rectangle for magnification
Dim src_x As Integer = mx - (mag.radius / mag.zoom)
Dim src_y As Integer = my - (mag.radius / mag.zoom)
Dim src_w As Integer = (mag.radius * 2) / mag.zoom
Dim src_h As Integer = (mag.radius * 2) / mag.zoom
' Ensure source coordinates are within bounds
If src_x < 0 Then src_x = 0
If src_y < 0 Then src_y = 0
If src_x + src_w >= SCREEN_WIDTH Then src_w = SCREEN_WIDTH - src_x - 1
If src_y + src_h >= SCREEN_HEIGHT Then src_h = SCREEN_HEIGHT - src_y - 1
' Clear magnifying glass buffer
ImageDestroy mag_buffer
mag_buffer = ImageCreate(mag.radius * 2, mag.radius * 2)
' Copy and scale the region
Put mag_buffer, (0, 0), background_buffer, (src_x, src_y)-(src_x + src_w, src_y + src_h), PSet
' Draw the magnified circular area
Dim dest_x As Integer = mx - mag.radius
Dim dest_y As Integer = my - mag.radius
' Draw circle background
Circle (mx, my), mag.radius + 2, RGB(100, 100, 100), , , , F
Circle (mx, my), mag.radius, RGB(255, 255, 255), , , , F
' Apply circular clipping and draw magnified content
For cy As Integer = -mag.radius To mag.radius
For cx As Integer = -mag.radius To mag.radius
Dim dist As Single = Sqr(cx * cx + cy * cy)
If dist <= mag.radius Then
Dim src_px As Integer = (cx + mag.radius) / mag.zoom
Dim src_py As Integer = (cy + mag.radius) / mag.zoom
If src_px >= 0 And src_px < mag.radius * 2 And src_py >= 0 And src_py < mag.radius * 2 Then
Dim pixel_color As UInteger = Point(src_x + src_px, src_y + src_py, background_buffer)
PSet (mx + cx, my + cy), pixel_color
End If
End If
Next
Next
' Draw magnifying glass border
Circle (mx, my), mag.radius, RGB(50, 50, 50), , , 3
Circle (mx, my), mag.radius - 1, RGB(200, 200, 200), , , 1
' Draw handle
Dim handle_x As Integer = mx + mag.radius * 0.7
Dim handle_y As Integer = my + mag.radius * 0.7
Line (handle_x, handle_y)-(handle_x + 30, handle_y + 30), RGB(139, 69, 19), , &H1111
Circle (handle_x + 30, handle_y + 30), 8, RGB(160, 82, 45), , , , F
End Sub
' Main program loop
Sub MainLoop()
Dim mx As Integer, my As Integer, mb As Integer
Dim key As String
Do
' Get mouse input
GetMouse mx, my, , mb
' Get keyboard input
key = InKey
' Clear screen and redraw background
Cls
Put (0, 0), background_buffer, PSet
' Handle mouse input
If mb And 1 Then ' Left mouse button
mag.active = 1
mag.x = mx
mag.y = my
ElseIf mb And 2 Then ' Right mouse button
mag.active = 0
End If
' Update magnifying glass position if active
If mag.active Then
mag.x = mx
mag.y = my
ApplyMagnifyingGlass(mag.x, mag.y)
End If
' Draw instructions
Draw String (10, 10), "Left Click: Activate Magnifying Glass", RGB(255, 255, 255)
Draw String (10, 25), "Right Click: Deactivate", RGB(255, 255, 255)
Draw String (10, 40), "ESC: Exit", RGB(255, 255, 255)
Draw String (10, 55), "Zoom: " + Str(mag.zoom) + "x", RGB(255, 255, 255)
' Handle keyboard input
Select Case UCase(key)
Case "+"
If mag.zoom < 5 Then mag.zoom += 0.5
Case "-"
If mag.zoom > 1 Then mag.zoom -= 0.5
Case Chr(27) ' ESC key
Exit Do
End Select
' Refresh display
Sleep 16 ' Approximately 60 FPS
Loop
End Sub
' Cleanup resources
Sub Cleanup()
If background_buffer <> 0 Then ImageDestroy background_buffer
If mag_buffer <> 0 Then ImageDestroy mag_buffer
End Sub
' Main program
Sub Main()
' Initialize graphics mode
ScreenRes SCREEN_WIDTH, SCREEN_HEIGHT, 32
WindowTitle "FreeBasic Magnifying Glass Tool"
' Initialize magnifying glass
InitMagnifyingGlass()
' Draw initial background
DrawBackground()
' Run main loop
MainLoop()
' Cleanup
Cleanup()
End Sub
' Program entry point
Main()
Imagine it like this: someone has just placed a co-programmer in your backyard. You don't know them yet, and they might seem unfamiliar—they're a foreigner from China. But give them a chance. Assign them a task and see what they can do for you. Don't be prejudiced; they're genuinely kind and incredibly talented. And no, you don't even need to learn Chinese.
#AIProgramming #CrossCulturalCollaboration #TechDiversity #GlobalTalent #Inclusion
#TechHistory #Programming #Assembler #Coding #Innovation #SoftwareDevelopment #NerdTalk 💻🤓⚙️🔍🔢🧠✨