ListIcon FillByGadget

Share your advanced PureBasic knowledge/code with the community.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8433
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

ListIcon FillByGadget

Post by netmaestro »

This sample allows the City field of the ListIcon gadget to be filled in by the user. He clicks a subitem in column 3 and he's given a ComboBox gadget to choose a city from. When he chooses one, the ComboBox goes away and the subitem is filled with the choice. Clicking elsewhere on the Listicon without making a selection cancels the action and the Combobox goes away.

It is accomplished in three steps: One, the ListIcon is placed into OwnerDrawFixed mode so that the #WM_MEASUREITEM message can be intercepted and the rowheight of our choice applied. In this case 20 is appropriate, as that is the height of the ComboBox we're using. This is done in the main window callback. Next, the ListIcon is subclassed and the hit tests are processed to give the index, size and location of the subitem to update. Third, the change event of the combobox is caught in the main loop and its contents used to update the current subitem. Here's the code:

Code: Select all

;================================================================ 
; Program:            ListIcon FillByGadget Sample 
; Author:             netmaestro 
; Date:               January 7, 2007 
; Target OS:          Windows All 
; Target Compiler:    PureBasic 4.02 
; License:            Free, Unrestricted, Credit appreciated 
;                     but not required 
;================================================================ 

#LVM_SUBITEMHITTEST = #LVM_FIRST + 57 
#LVM_GETSUBITEMRECT = #LVM_FIRST + 56 

Global oldproc 
Global currentitem, currentsubitem 

Procedure MainWindowCallBack(hwnd, msg, wparam, lparam) 
  result = #PB_ProcessPureBasicEvents 

  Select msg 
    Case #WM_DRAWITEM 
      
      *lpdis.DRAWITEMSTRUCT = lparam 
      Dim itemrect.RECT(3) 
      For i = 1 To 3 
        RtlZeroMemory_(@itemrect(i),SizeOf(RECT)) 
        itemrect(i)\top = i 
        SendMessage_(*lpdis\hwndItem, #LVM_GETSUBITEMRECT, *lpdis\itemid, @itemrect(i)) 
        text$ = GetGadgetItemText(GetDlgCtrlID_(*lpdis\hwndItem), *lpdis\itemid, i) 
        SelectObject_(*lpdis\hDC, GetStockObject_(#NULL_PEN)) 
        WhiteBrush = CreateSolidBrush_(#White) 
        SelectObject_(*lpdis\hDC, WhiteBrush) 
        Rectangle_(*lpdis\hDC, itemrect(i)\left+4, itemrect(i)\top+4, itemrect(i)\right, itemrect(i)\bottom) 
        TextOut_(*lpdis\hDC, itemrect(i)\left+4, itemrect(i)\top+4, text$, Len(text$)) 
        DeleteObject_(WhiteBrush) 
      Next 

    Case #WM_MEASUREITEM 
    
      *lpmis.MEASUREITEMSTRUCT = lparam 
      *lpmis\itemheight = 20 
      
  EndSelect 
  
  ProcedureReturn result 
  
EndProcedure 

Procedure SubClass_LV(hwnd, msg, wparam, lparam) 
  result = CallWindowProc_(oldproc, hwnd, msg, wparam, lparam) 
  
  If msg = #WM_RBUTTONDOWN Or msg = #WM_LBUTTONDOWN 
  
    GetCursorPos_(@cp.POINT) 
    MapWindowPoints_(0,hwnd,@cp,1) 
    HitInfo.LVHITTESTINFO 
    Hitinfo\pt\x = cp\x 
    HitInfo\pt\y = cp\y 
    SendMessage_(hwnd,#LVM_SUBITEMHITTEST ,0,@HitInfo) 
    If hitinfo\isubitem > 0 And HitInfo\iItem >= 0 
      currentitem    = hitinfo\iitem 
      currentsubitem = hitinfo\isubitem 
      RtlZeroMemory_(@itemrect.RECT,SizeOf(RECT)) 
      itemrect\top = hitinfo\iSubItem 
      SendMessage_(hwnd,#LVM_GETSUBITEMRECT, hitinfo\iitem, @itemrect) 
      If HitInfo\iSubItem = 3 
        ResizeGadget(1, itemrect\left, itemrect\top, itemrect\right-itemrect\left, itemrect\bottom-itemrect\top) 
        SetGadgetState(1,0) 
        HideGadget(1,0) 
      Else 
        HideGadget(1,1) 
      EndIf 
    Else
      HideGadget(1,1)
    EndIf 
    
  EndIf 
  
  ProcedureReturn result 
  
EndProcedure 

OpenWindow(0,0,0,320,240,"",$CF0001) 
SetWindowCallback(@MainWindowCallBack()) 
CreateGadgetList(WindowID(0)) 

ListIconGadget(0,0,0,320,240,"",0,#PB_ListIcon_GridLines|#LVS_OWNERDRAWFIXED) 
oldproc = SetWindowLong_(GadgetID(0), #GWL_WNDPROC, @SubClass_LV()) 
AddGadgetColumn(0,1,"FirstName",100) 
AddGadgetColumn(0,2,"LastName",100) 
AddGadgetColumn(0,3,"City",115) 
AddGadgetItem(0, -1, Chr(10) + "Lloyd" + Chr(10) + "Gallant" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Eric" + Chr(10) + "Penrose" + Chr(10)  ) 
AddGadgetItem(0, -1, Chr(10) + "Mark" + Chr(10) + "Dutton" + Chr(10)   ) 
AddGadgetItem(0, -1, Chr(10) + "Tim" + Chr(10) + "Knechtel" + Chr(10)  ) 

ComboBoxGadget(1, 0,20,100,200,#PB_Window_Invisible) 
SetParent_(GadgetID(1),GadgetID(0)) 
AddGadgetItem(1,0,"") 
AddGadgetItem(1,1,"Toronto") 
AddGadgetItem(1,2,"Kitchener") 
AddGadgetItem(1,3,"Waterloo") 
AddGadgetItem(1,4,"Barrie") 
HideGadget(1,1) 

Repeat 

  EventID = WaitWindowEvent() 
  Select EventID 
    Case #PB_Event_Gadget 
      Select EventGadget() 
        Case 1 
          If EventType() = 1 
            SetGadgetItemText(0, currentitem, GetGadgetText(1), currentsubitem) 
            HideGadget(1,1) 
          EndIf 
      EndSelect 
  EndSelect 

Until EventID = #WM_CLOSE 
Very little of this code is specific to this particular set of data. This code can very easily be adapted to work in any project with few changes. Number of columns in the callback is one to customize, which column is getting the combobox in the subclass is another. Apart from the combobox items, that's about it.
Last edited by netmaestro on Tue Jan 09, 2007 8:32 pm, edited 1 time in total.
BERESHEIT
va!n
Addict
Addict
Posts: 1104
Joined: Wed Apr 20, 2005 12:48 pm

Post by va!n »

nice work! :)
va!n aka Thorsten

Intel i7-980X Extreme Edition, 12 GB DDR3, Radeon 5870 2GB, Windows7 x64,
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

Re: ListIcon FillByGadget

Post by NoahPhense »

Nice work Net ..

- np
Tranquil
Addict
Addict
Posts: 950
Joined: Mon Apr 28, 2003 2:22 pm
Location: Europe

Post by Tranquil »

This rock!! VERY NICE! Many thanks for sharing!
Tranquil
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

Yes indeed!

Another nice one.

cheers
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4749
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Post by Fangbeast »

When the list is filled with data and you click on a valid line to enter data, the combobox pops up.

If you click anywhere on a line with data in it (without selecting an item from the combobox), the combobox vanishes. That's okay.

If you click anywhere on a line without data in it (unpopulated listicon line) without selecting an item from the combobox, the does not vanish. not okay.

Where the following line is:

Else
HideGadget(1,1)
EndIf


in the "SubClass_LV(hwnd, msg, wparam, lparam)" procedure,
put another

Else
HideGadget(1,1)


immediately under it so the combobox vanishes immediately by clicking ANYWHERE on the listicongadget if you haven't selected an item.
Amateur Radio, D-STAR/VK3HAF
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8433
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

OK, thanks for pointing that out. I've updated the code in the first post to add the extra check.
BERESHEIT
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4749
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Post by Fangbeast »

netmaestro wrote:OK, thanks for pointing that out. I've updated the code in the first post to add the extra check.
I'm amazed that my tiny brain was able to figure that much out!
Amateur Radio, D-STAR/VK3HAF
techjunkie
Addict
Addict
Posts: 1126
Joined: Wed Oct 15, 2003 12:40 am
Location: Sweden
Contact:

Post by techjunkie »

Another great code snippet from the one and only Netmaestro! :D Thanks!!
Image
(\__/)
(='.'=) This is Bunny. Copy and paste Bunny into your
(")_(") signature to help him gain world domination.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Very nice netty. 8)

Hope you don't mind, but I've thrown in a couple of checks which removes the ComboBox whenever the user resizes a column or scrolls the listicon etc. Without this you get all sorts of repainting issues when the user resizes a column etc.

Code: Select all

;================================================================ 
; Program:            ListIcon FillByGadget Sample 
; Author:             netmaestro 
; Date:               January 7, 2007 
; Target OS:          Windows All 
; Target Compiler:    PureBasic 4.02 
; License:            Free, Unrestricted, Credit appreciated 
;                     but not required 
;================================================================ 

#LVM_SUBITEMHITTEST = #LVM_FIRST + 57 
#LVM_GETSUBITEMRECT = #LVM_FIRST + 56 

Global oldproc 
Global currentitem, currentsubitem 

Procedure MainWindowCallBack(hwnd, msg, wparam, lparam) 
  result = #PB_ProcessPureBasicEvents 

  Select msg 
    Case #WM_DRAWITEM 
      
      *lpdis.DRAWITEMSTRUCT = lparam 
      Dim itemrect.RECT(3) 
      For i = 1 To 3 
        RtlZeroMemory_(@itemrect(i),SizeOf(RECT)) 
        itemrect(i)\top = i 
        SendMessage_(*lpdis\hwndItem, #LVM_GETSUBITEMRECT, *lpdis\itemid, @itemrect(i)) 
        text$ = GetGadgetItemText(GetDlgCtrlID_(*lpdis\hwndItem), *lpdis\itemid, i) 
        SelectObject_(*lpdis\hDC, GetStockObject_(#NULL_PEN)) 
        WhiteBrush = CreateSolidBrush_(#White) 
        SelectObject_(*lpdis\hDC, WhiteBrush) 
        Rectangle_(*lpdis\hDC, itemrect(i)\left+4, itemrect(i)\top+4, itemrect(i)\right, itemrect(i)\bottom) 
        TextOut_(*lpdis\hDC, itemrect(i)\left+4, itemrect(i)\top+4, text$, Len(text$)) 
        DeleteObject_(WhiteBrush) 
      Next 

    Case #WM_MEASUREITEM 
    
      *lpmis.MEASUREITEMSTRUCT = lparam 
      *lpmis\itemheight = 20 
      

  EndSelect 
  
  ProcedureReturn result 
  
EndProcedure 

Procedure SubClass_LV(hwnd, msg, wparam, lparam) 
  result = CallWindowProc_(oldproc, hwnd, msg, wparam, lparam) 
  
  If msg = #WM_RBUTTONDOWN Or msg = #WM_LBUTTONDOWN
    GetCursorPos_(@cp.POINT) 
    MapWindowPoints_(0,hwnd,@cp,1) 
    HitInfo.LVHITTESTINFO 
    Hitinfo\pt\x = cp\x 
    HitInfo\pt\y = cp\y 
    SendMessage_(hwnd,#LVM_SUBITEMHITTEST ,0,@HitInfo) 
    If hitinfo\isubitem > 0 And HitInfo\iItem >= 0 
      currentitem    = hitinfo\iitem 
      currentsubitem = hitinfo\isubitem 
      RtlZeroMemory_(@itemrect.RECT,SizeOf(RECT)) 
      itemrect\top = hitinfo\iSubItem 
      SendMessage_(hwnd,#LVM_GETSUBITEMRECT, hitinfo\iitem, @itemrect) 
      If HitInfo\iSubItem = 3 
        ResizeGadget(1, itemrect\left, itemrect\top, itemrect\right-itemrect\left, itemrect\bottom-itemrect\top) 
        SetGadgetState(1,0) 
        HideGadget(1,0) 
      Else 
        HideGadget(1,1) 
      EndIf 
    Else 
      HideGadget(1,1) 
    EndIf 
  ElseIf msg=#WM_HSCROLL Or msg=#WM_VSCROLL
    HideGadget(1,1) 
  ElseIf msg=#WM_NOTIFY
    *nmHEADER.HD_NOTIFY = lParam 
    Select *nmHEADER\hdr\code
      Case #HDN_BEGINTRACK, #HDN_BEGINTRACKW
        HideGadget(1,1) 
    EndSelect

  EndIf 
  
  ProcedureReturn result 
  
EndProcedure 

OpenWindow(0,0,0,320,240,"",$CF0001) 
SetWindowCallback(@MainWindowCallBack()) 
CreateGadgetList(WindowID(0)) 

ListIconGadget(0,0,0,320,240,"",0,#PB_ListIcon_GridLines|#LVS_OWNERDRAWFIXED) 
oldproc = SetWindowLong_(GadgetID(0), #GWL_WNDPROC, @SubClass_LV()) 
AddGadgetColumn(0,1,"FirstName",100) 
AddGadgetColumn(0,2,"LastName",100) 
AddGadgetColumn(0,3,"City",115) 
AddGadgetItem(0, -1, Chr(10) + "Lloyd" + Chr(10) + "Gallant" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Eric" + Chr(10) + "Penrose" + Chr(10)  ) 
AddGadgetItem(0, -1, Chr(10) + "Mark" + Chr(10) + "Dutton" + Chr(10)   ) 
AddGadgetItem(0, -1, Chr(10) + "Tim" + Chr(10) + "Knechtel" + Chr(10)  ) 

ComboBoxGadget(1, 0,20,100,200,#PB_Window_Invisible) 
SetParent_(GadgetID(1),GadgetID(0)) 
AddGadgetItem(1,0,"") 
AddGadgetItem(1,1,"Toronto") 
AddGadgetItem(1,2,"Kitchener") 
AddGadgetItem(1,3,"Waterloo") 
AddGadgetItem(1,4,"Barrie") 
HideGadget(1,1) 

Repeat 

  EventID = WaitWindowEvent() 
  Select EventID 
    Case #PB_Event_Gadget 
      Select EventGadget() 
        Case 1 
          If EventType() = 1 
            SetGadgetItemText(0, currentitem, GetGadgetText(1), currentsubitem) 
            HideGadget(1,1) 
          EndIf 
      EndSelect 
  EndSelect 

Until EventID = #WM_CLOSE 
I may look like a mule, but I'm not a complete ass.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8433
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

@srod, thanks so much for pointing that out, believe it or not I didn't even consider the possibility that someone would suddenly be siezed with the urge to resize a column while editing. But of course it happens all the time. What do you think of this option, rather than kicking his edit:

Code: Select all

;================================================================ 
; Program:            ListIcon FillByGadget Sample 
; Author:             netmaestro 
; Date:               January 7, 2007 
; Target OS:          Windows All 
; Target Compiler:    PureBasic 4.02 
; License:            Free, Unrestricted, Credit appreciated 
;                     but not required 
;================================================================ 

#LVM_SUBITEMHITTEST = #LVM_FIRST + 57 
#LVM_GETSUBITEMRECT = #LVM_FIRST + 56 

Global oldproc 
Global currentitem, currentsubitem 

Procedure MainWindowCallBack(hwnd, msg, wparam, lparam) 
  result = #PB_ProcessPureBasicEvents 

  Select msg 
    Case #WM_DRAWITEM 
      
      *lpdis.DRAWITEMSTRUCT = lparam 
      Dim itemrect.RECT(3) 
      For i = 1 To 3 
        RtlZeroMemory_(@itemrect(i),SizeOf(RECT)) 
        itemrect(i)\top = i 
        SendMessage_(*lpdis\hwndItem, #LVM_GETSUBITEMRECT, *lpdis\itemid, @itemrect(i)) 
        text$ = GetGadgetItemText(GetDlgCtrlID_(*lpdis\hwndItem), *lpdis\itemid, i) 
        SelectObject_(*lpdis\hDC, GetStockObject_(#NULL_PEN)) 
        WhiteBrush = CreateSolidBrush_(#White) 
        SelectObject_(*lpdis\hDC, WhiteBrush) 
        Rectangle_(*lpdis\hDC, itemrect(i)\left, itemrect(i)\top, itemrect(i)\right, itemrect(i)\bottom) 
        TextOut_(*lpdis\hDC, itemrect(i)\left+4, itemrect(i)\top+4, text$, Len(text$)) 
        DeleteObject_(WhiteBrush) 
      Next 

    Case #WM_MEASUREITEM 
    
      *lpmis.MEASUREITEMSTRUCT = lparam 
      *lpmis\itemheight = 20 
      

  EndSelect 
  
  ProcedureReturn result 
  
EndProcedure 

Procedure ResizeCombo(hwnd)
  RtlZeroMemory_(@itemrect.RECT,SizeOf(RECT)) 
  itemrect\top = currentsubitem 
  SendMessage_(hwnd,#LVM_GETSUBITEMRECT, currentitem, @itemrect)       
  ResizeGadget(1,itemrect\left,itemrect\top,itemrect\right-itemrect\left,#PB_Ignore)
  InvalidateRect_(GadgetID(1),0,1)
EndProcedure

Procedure SubClass_LV(hwnd, msg, wparam, lparam) 
  result = CallWindowProc_(oldproc, hwnd, msg, wparam, lparam) 
  
  If msg = #WM_RBUTTONDOWN Or msg = #WM_LBUTTONDOWN 
    GetCursorPos_(@cp.POINT) 
    MapWindowPoints_(0,hwnd,@cp,1) 
    HitInfo.LVHITTESTINFO 
    Hitinfo\pt\x = cp\x 
    HitInfo\pt\y = cp\y 
    SendMessage_(hwnd,#LVM_SUBITEMHITTEST ,0,@HitInfo) 
    If hitinfo\isubitem > 0 And HitInfo\iItem >= 0 
      currentitem    = hitinfo\iitem 
      currentsubitem = hitinfo\isubitem 
      RtlZeroMemory_(@itemrect.RECT,SizeOf(RECT)) 
      itemrect\top = hitinfo\iSubItem 
      SendMessage_(hwnd,#LVM_GETSUBITEMRECT, hitinfo\iitem, @itemrect) 
      If HitInfo\iSubItem = 3 
        ResizeGadget(1, itemrect\left, itemrect\top, itemrect\right-itemrect\left, itemrect\bottom-itemrect\top) 
        SetGadgetState(1,0) 
        HideGadget(1,0) 
      Else 
        HideGadget(1,1) 
      EndIf 
    Else 
      HideGadget(1,1) 
    EndIf 
  ElseIf msg=#WM_HSCROLL Or msg=#WM_VSCROLL 
    ResizeCombo(hwnd)
  ElseIf msg=#WM_NOTIFY 
    *nmHEADER.HD_NOTIFY = lParam 
    Select *nmHEADER\hdr\code 
      Case #HDN_ITEMCHANGING
        ResizeCombo(hwnd)
    EndSelect 

  EndIf 
  
  ProcedureReturn result 
  
EndProcedure 

OpenWindow(0,0,0,320,240,"",$CF0001) 
SetWindowCallback(@MainWindowCallBack()) 
CreateGadgetList(WindowID(0)) 

ListIconGadget(0,0,0,320,240,"",0,#PB_ListIcon_GridLines|#LVS_OWNERDRAWFIXED) 
oldproc = SetWindowLong_(GadgetID(0), #GWL_WNDPROC, @SubClass_LV()) 
AddGadgetColumn(0,1,"FirstName",100) 
AddGadgetColumn(0,2,"LastName",100) 
AddGadgetColumn(0,3,"City",115) 
AddGadgetItem(0, -1, Chr(10) + "Lloyd" + Chr(10) + "Gallant" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Eric" + Chr(10) + "Penrose" + Chr(10)  ) 
AddGadgetItem(0, -1, Chr(10) + "Mark" + Chr(10) + "Dutton" + Chr(10)   ) 
AddGadgetItem(0, -1, Chr(10) + "Tim" + Chr(10) + "Knechtel" + Chr(10)  ) 

ComboBoxGadget(1, 0,20,100,200,#PB_Window_Invisible) 
SetParent_(GadgetID(1),GadgetID(0)) 
AddGadgetItem(1,0,"") 
AddGadgetItem(1,1,"Toronto") 
AddGadgetItem(1,2,"Kitchener") 
AddGadgetItem(1,3,"Waterloo") 
AddGadgetItem(1,4,"Barrie") 
HideGadget(1,1) 

Repeat 

  EventID = WaitWindowEvent() 
  Select EventID 
    Case #PB_Event_Gadget 
      Select EventGadget() 
        Case 1 
          If EventType() = 1 
            SetGadgetItemText(0, currentitem, GetGadgetText(1), currentsubitem) 
            HideGadget(1,1) 
          EndIf 
      EndSelect 
  EndSelect 

Until EventID = #WM_CLOSE 
BERESHEIT
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

Nicely done once again netmaestro :)
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

netmaestro wrote:@srod, thanks so much for pointing that out, believe it or not I didn't even consider the possibility that someone would suddenly be siezed with the urge to resize a column while editing. But of course it happens all the time. What do you think of this option, rather than kicking his edit:
That's great netmaestro, much better! :)

I had to contend with this with egrid and whilst I originally took your approach of resizing on the fly, I found that with all the custom drawing I was doing anyway, the string gadget edit cells proved problematic (no problem with the combobox). I won't bore you with the details (it was to do with the customised resizing code I used - the default way of resizing proved too slow for a fully customised egrid) but I ended up simply removing the string gadget / combobox etc. whenever the user resized a column (with the option of replacing it afterwards!)

Nice code, I think a lot of people will find a good use for this.
I may look like a mule, but I'm not a complete ass.
User avatar
Joakim Christiansen
Addict
Addict
Posts: 2452
Joined: Wed Dec 22, 2004 4:12 pm
Location: Norway
Contact:

Post by Joakim Christiansen »

Designing good GUIs is PureBasic weakest point, I really hate ALWAYS having to do insanely much research each time I want to make a little advanced GUI (which is super easy in VisualStudio btw)...
Don't get me wrong, I love PureBasic but the Linux compatibility for gadgets hurts the all the cool features you could get if it was specialized for windows.

But anyway, about this example:
I think the ComboBox should always be visible, that looks to me like the standard solution. It should also use a version without xp skin when inside a list like this. And btw the last example doesn't resize properly when you disable the xp skin support (at least not on Vista).
I like logic, hence I dislike humans but love computers.
Heathen
Enthusiast
Enthusiast
Posts: 498
Joined: Tue Sep 27, 2005 6:54 pm
Location: At my pc coding..

Post by Heathen »

edit: Nice example
I love Purebasic.
Post Reply