|
Post by tenochtitlanuk on Nov 14, 2019 17:26:22 GMT -5
Perhaps a quirk of me running LB under Linux/Wine but that Rosetta Code failed for me- could select a colour, and it then drew a partial horizontal line only, across white and black. Left for a while and the machine froze- had to hit reset! Never had that before....
|
|
|
Post by Rod on Nov 15, 2019 5:15:47 GMT -5
The flood fill rosetta code had a number of quirks for me. It also did not run on my PC The main culprit was setting the brush using backcolor instead of color. But it was also passing globals to subs and whats with floating point numbers describing screen width?
I simplified it right down and used mostly native commands to get info rather than API for the sake of API.
nomainwin WindowWidth = 300 WindowHeight = 300 UpperLeftX=int((DisplayWidth-WindowWidth)/2) UpperLeftY=int((DisplayHeight-WindowHeight)/2) graphicbox #main.gbox, 0,0,300,300 open "Flood Fill - Click a Color" For Window As #main #main "trapclose quit" #main.gbox "down; fill black; place 125 125; backcolor white" #main.gbox "circlefilled 115; place 105 105; backcolor black" #main.gbox "circlefilled 50; flush floodfill" #main.gbox "when leftButtonUp gBoxClick" #main.gbox "size 1"
'get the handle of the graphicbox and its associated DC global hDC,hWnd hWnd=hwnd(#main.gbox) calldll #user32, "GetDC", hWnd as ulong, hDC as ulong Wait
sub quit handle$ 'release the DC calldll #user32,"ReleaseDC", hWnd as ulong, hDC as ulong, ret as long close #main end end sub
sub gBoxClick handle$, x, y 'stop mouse handling #handle$ "when leftButtonUp" 'get the pixel color clicked targetRGB = getPixel(x,y) 'get the desired color colordialog "", replacementColor$ if replacementColor$ = "" then exit sub 'set the drawing pen #main.gbox "backcolor " + replacementColor$ 'flood fill calldll #gdi32, "ExtFloodFill",hDC as ulong,x as long,y as long,targetRGB as long,_FLOODFILLSURFACE as long,result as long 'capture the drawing into a Liberty segment, delete the original first #main.gbox "delsegment floodfill" #main.gbox "getbmp bmp 0 0 500 500; cls; drawbmp bmp 0 0; flush floodfill" unloadbmp "bmp" 'start mouse handling again #handle$ "when leftButtonUp gBoxClick" End Sub
function getPixel(x,y) calldll #gdi32, "GetPixel", hDC as ulong, x as long, y as long, getPixel as long end function
|
|
|
Post by tenochtitlanuk on Nov 15, 2019 7:10:35 GMT -5
Very close code to what I'd have used! Should we change the Rosetta Code entry, or contact it's originator?? I remember others altering or replacing code I put up, but don't remember myself editing any supplied by others. I think I remember my Rosetta Code password- in recent years I've looked at it for new ideas and methods without logging in, but it's several years since I added or edited a LB solution.
|
|
|
Post by Rod on Nov 15, 2019 7:56:25 GMT -5
Actually now that I have read the task properly it was really seeking an example of how to flood fill an area, so not using the floodfill API. I will try and look at it again, the original poster was using getpixel then simply set pixel iteratively. So long and slow and it still does not work on my PC. But the example should show how you would cover the entire area.
|
|
|
Post by Brandon Parker on Nov 15, 2019 13:17:04 GMT -5
The example was to flood fill an area selected without using a predefined function (i.e. create the algorithm yourself). I know this code used to work, but for some reason, it is no longer working on my machine either.
{:0)
Brandon Parker
|
|
|
Post by Brandon Parker on Nov 15, 2019 14:36:38 GMT -5
To me, it looks like something has changed with how the GetPixel function works vs. how it was working when I test it. It looks like it is not up updating the pixel color value correctly and is thus not doing what it is supposed to.
{:0)
Brandon Parker
|
|
|
Post by Brandon Parker on Nov 15, 2019 20:41:20 GMT -5
Well, after digging through the code scratching my head vigorously all day long I have finally figured out what the problem is. This code was written back when Windows 7 was the name of the game, and although DPI awareness was definitely around it seems to bite things harder now that monitors have vastly improved resolution (my new laptop has awesome resolution). I stumbled upon a post where someone was having the exact same issue and it turned out that the reason is the whole DPI awareness debacle and what "is" and what "is not" automatically scaled. It looks like the mouse information is automatically scaled, but other stuff (read program in general) is not scaled/dealt with automatically.
Having the program call the SetProcessDPIAware function in the User32 library completely resolves the issue. As a bonus, it appears to make the Liberty BASIC IDE step into line with DPI awareness as well when the code is executed via the IDE.
I also find that I now have to add a delay after the GraphicBox command to set the color or else the program completes immediately. At least to me and my machine, it looks like the GraphicBox Color change command is asynchronous and my machine buzzes through the subsequent code prior to the color actually being changed from the default black to the color picker choice.
The code below should work, but you may have to increase the delay in the gBoxClick subroutine just prior to the call to the FloodFill function if you have a super-duper fast machine.
'This example requires the Windows API NoMainWin
result = SetProcessDPIAware()
WindowWidth = 267.5 WindowHeight = 292.5 UpperLeftX=int((DisplayWidth-WindowWidth)/2) UpperLeftY=int((DisplayHeight-WindowHeight)/2)
Global hDC : hDC = GetDC(0) Struct point, x As long, y As long Struct RGB, Red As long, Green As long, Blue As long Struct rect, left As long, top As long, right As long, bottom As long
StyleBits #main.gbox, 0, _WS_BORDER, 0, 0 GraphicBox #main.gbox, 2.5, 2.5, 253, 252
Open "Flood Fill - Click a Color" For Window As #main #main "TrapClose quit" #main.gbox "Down; Fill Black; Place 125 125; BackColor White; " _ + "CircleFilled 115; Place 105 105; BackColor Black; CircleFilled 50; Flush" #main.gbox "When leftButtonUp gBoxClick" #main.gbox "Size 1" Wait
Sub quit handle$ Call ReleaseDC 0, hDC Close #main End End Sub
Sub gBoxClick handle$, mX, mY #main.gbox "When leftButtonUp" result = GetCursorPos() targetRGB = GetPixel(hDC, point.x.struct, point.y.struct) ColorDialog "", replacementColor$ If replacementColor$ = "" Then Exit Sub #main.gbox "Color " + Word$(replacementColor$, 1) + " " + Word$(replacementColor$, 2) + " " + Word$(replacementColor$, 3) CallDLL #kernel32, "Sleep", 250 As long, ret As void result = FloodFill(mX, mY, targetRGB) #main.gbox "DelSegment FloodFill" #main.gbox "GetBMP FloodFill 0 0 500 500; CLS; DrawBMP FloodFill 0 0; Flush FloodFill" Notice "Complete!" #main.gbox "When leftButtonUp gBoxClick" End Sub
Sub ReleaseDC hWnd, hDC CallDLL #user32,"ReleaseDC", hWnd As uLong, hDC As uLong, ret As Long End Sub
Function GetDC(hWnd) CallDLL #user32, "GetDC", hWnd As uLong, GetDC As uLong End Function
Function GetCursorPos() CallDLL #user32, "GetCursorPos", point As struct, GetCursorPos As uLong End Function
Function GetPixel(hDC, x, y) CallDLL #gdi32, "GetPixel", hDC As uLong, x As long, y As long, GetPixel As long End Function
Function GetWindowRect(hWnd) 'Get ClientRectangle CallDLL #user32, "GetWindowRect", hWnd As ulong, rect As struct, GetWindowRect As ulong End Function
Function FloodFill(mouseXX, mouseYY, targetColor) Scan result = GetWindowRect(Hwnd(#main.gbox)) X = Int(mouseXX + rect.left.struct) Y = Int(mouseYY + rect.top.struct) If (GetPixel(hDC, X, Y) <> targetColor) Then Exit Function Else CLS #main.gbox, "Set " + str$(mouseXX) + " " + str$(mouseYY) End If If (mouseXX > 0) And (mouseXX < 253) Then result = FloodFill((mouseXX - 1), mouseYY, targetColor) result = FloodFill((mouseXX + 1), mouseYY, targetColor) End If If (mouseYY > 0) And (mouseYY < 252) Then result = FloodFill(mouseXX, (mouseYY + 1), targetColor) result = FloodFill(mouseXX, (mouseYY - 1), targetColor) End If End Function
Function SetProcessDPIAware() CallDLL #user32, "SetProcessDPIAware", SetProcessDPIAware As long End Function I also removed the use of MouseX and Mouse Y as well; I used mX and mY in their place. This, while is should not matter in this case, was just something of an oversight.
Should you want a different type of Floodfill method, you might like this one. It works slightly differently ...
Function FloodFillAll(mouseXX, mouseYY, targetColor) For xpos = 0 To 253 For ypos = 0 To 252 result = GetWindowRect(Hwnd(#main.gbox)) X = Int(xpos + rect.left.struct) Y = Int(ypos + rect.top.struct) If (GetPixel(hDC, X, Y) = targetColor) Then #main.gbox "Set " + str$(xpos) + " " + str$(ypos) End If Next ypos Next xpos End Function
We should probably continue this discussion on a separate post if you guys/gals are up for it.
{:0)
Brandon Parker
|
|
|
Post by Rod on Nov 16, 2019 6:10:01 GMT -5
Doing it with the bare minimum of API code requires only getPixel() We are not going to get a raft of API access in 5 only a few hand coded lookalikes. Some may use API calls but I think most will be smalltalk code mimicking API. Which throws up a question for me, the Device Context (DC) I needed the DC to complete this code will I have access to it in 5 or is it not required?
nomainwin WindowWidth = 300 WindowHeight = 300 UpperLeftX=int((DisplayWidth-WindowWidth)/2) UpperLeftY=int((DisplayHeight-WindowHeight)/2) graphicbox #main.gbox, 0,0,300,300 open "Flood Fill - Click a Color" For Window As #main #main "trapclose quit" #main.gbox "down; fill black; place 125 125; backcolor white" #main.gbox "circlefilled 115; place 105 105; backcolor black" #main.gbox "circlefilled 50; flush floodfill" #main.gbox "when leftButtonUp gBoxClick" #main.gbox "size 1"
'get the handle of the graphicbox and its associated DC global hDC,hWnd hWnd=hwnd(#main.gbox) calldll #user32, "GetDC", hWnd as ulong, hDC as ulong Wait
sub quit handle$ 'release the DC calldll #user32,"ReleaseDC", hWnd as ulong, hDC as ulong, ret as long close #main end end sub
sub gBoxClick handle$, x, y 'stop mouse handling #handle$ "when leftButtonUp" 'get the pixel color clicked target= getPixel(x,y) 'get the desired color colordialog "", color$ replacement = val(word$(color$,1))+256*val(word$(color$,2))+256*256*val(word$(color$,3)) if color$ = "" then exit sub 'set the drawing pen #main.gbox "color " + color$ nul=floodfill(x,y,target,replacement) 'start mouse handling again #handle$ "when leftButtonUp gBoxClick" End Sub
function floodfill(x,y,target,replacement) if target = replacement then exit function if getPixel(x,y) <> target then exit function else #main.gbox "set ";x;" ";y end if nul=floodfill(x,y+1,target,replacement) nul=floodfill(x,y-1,target,replacement) nul=floodfill(x-1,y,target,replacement) nul=floodfill(x+1,y,target,replacement) end function
function getPixel(x,y) calldll #gdi32, "GetPixel", hDC as ulong, x as long, y as long, getPixel as long end function
|
|
|
Post by Brandon Parker on Nov 16, 2019 13:00:29 GMT -5
I just remember that when the original code was written, there was an issue with the coordinates from Windows, and this was how it was implemented. Now considering the whole DPI thing, it makes more sense what might have been happening years ago.
Either way, it will be a moot point if Carl is able to give us a native GetPixel() function or even an entire Floodfill function on the back-end.
When LB 5 eventually does make it out of Alpha/Beta testing there will have to be a fork created on Rosetta Code to differentiate which version each implementation uses if there are things in one version that are not available in the other.
{:0)
Brandon R. Parker
|
|
|
Post by tenochtitlanuk on Nov 16, 2019 13:21:53 GMT -5
... still fails on Linux/Wine... But I'm, as ever, impressed by your deep familiarity with Window's 'innards'!
|
|
|
Post by Rod on Nov 16, 2019 18:05:03 GMT -5
Is it failing or is it just taking time? I am mightily impressed with Brandon's grip of API. It will be an ongoing resource for Liberty 4 which will persist. I think 5 will be an entirely new experience. Both will be fun.
|
|
|
Post by kaylab on Nov 19, 2019 20:25:32 GMT -5
Not quite only doable via API but ... AES-256 Cryptography SHA-256 Hashing
|
|
|
Post by donnybowers on Dec 6, 2019 4:09:36 GMT -5
I don't know how far off topic I am here, but I really wish there was a way to customize the dialog boxes. I actually have been working on my own file dialog program. I started this project for two reasons. First because I'm aware that my vision is getting weaker as I get older, and it's getting more and more difficult to see the generic file dialog styling that LB uses. Second is because I'm currently away from home and I'm using a laptop that has some issues with even using the Windows file dialog in Wine. I've been meaning to reinstall my Ubuntu based system (which I'm sure would resolve the issue), but didn't get around to it before leaving on this trip, and I just can't do it right now, possibly not until spring.
Anyway, as I said, I really want to start using a larger print file dialog and text editor for my work. I'm aware that LB5 is not at a stage where this idea should be a priority, but I would just like to suggest the idea of somehow having more control over font-size in the typical dialog box maybe some day in the future for folks who have visual issues. For now I plan to just work around it using my new "filedialog" program. Currently I only use it to load .txt, .htm, .html, .php, and .pdf files using other programs (i.e. ted text editor, geany, firefox and my system's default PDF reader).
|
|
|
Post by sarossell on Dec 6, 2019 15:49:24 GMT -5
Ooh! I don't know what you have in mind for control of the Raspberry Pi GPIO ports, but native commands would be awesome. Most other implementations use the WiringPi access library written in C (http://wiringpi.com/), but the programmer recently stopped development (August 6, 2019). It would be great if LB 5 had its own set of native commands that felt more like the kind of BASIC we all love. There are alternatives to WiringPi, but it sort of became the de facto solution.
|
|
|
Post by Carl Gundel on Dec 6, 2019 21:10:36 GMT -5
Ooh! I don't know what you have in mind for control of the Raspberry Pi GPIO ports, but native commands would be awesome. Most other implementations use the WiringPi access library written in C (http://wiringpi.com/), but the programmer recently stopped development (August 6, 2019). It would be great if LB 5 had its own set of native commands that felt more like the kind of BASIC we all love. There are alternatives to WiringPi, but it sort of became the de facto solution. You can already do GPIO in Liberty BASIC on the Pi because Raspian has a file system interface to access it. Any software that can read and write files can do GPIO on the Pi.
|
|