It is currently Fri Jan 18, 2019 11:21 am

All times are UTC + 1 hour




Post new topic Reply to topic  [ 29 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Re: determining item at top of Listview gadget
PostPosted: Sun Apr 05, 2015 11:16 pm 
Offline
Addict
Addict
User avatar

Joined: Thu Apr 21, 2005 2:38 pm
Posts: 1581
Location: Germany
Blue wrote:
Does anyone know how to figure out, using only PB code, which item is currently at the top of a Listview gadget ?
I know how to get this information using some API function, but i'm looking into a solution that would work on any platform.

Blue wrote:
But i'm looking for an all platforms solution, written with PB only code. :idea:

Some features can't be achieved without using API functions. And it's not necessary to rule out the use of API functions completely only because the resulting code wouldn't be cross-platform anymore. You simply have to implement the respective API functions for each OS. I have already put together a list with links to cross-platform code examples which use API functions to implement functions currently not available in PureBasic. And some of these functions have already become implemented natively as PB functions... :wink:

The above list contains already links to cross-platform examples to display a double-clicked row at the top of a ListIconGadget or display a selected row in the center of a ListIconGadget.

For your conveniance I have taken your code example and added the respective API functions for Linux and MacOS to determine the currently visible row at the top of your ListViewGadget. I have tested the modified example successfully on these operating systems:
- MacOS X 10.6.8 (Snow Leopard) x86
- Ubuntu 14.04 x64 with KDE
- Windows 7 x64 SP1

But this example has one problem which you wouldn't know if only working with Windows: in Windows the top row is normally always visible as a whole row whereras in Linux and MacOS it's possible that only a fraction of the current top row is visible. So as a result it's possible on Linux and MacOS that for example a top row of 0 is reported although the top row seems to be row 1 because only a very small (and nearly unvisible) part of top row 0 is displayed. To solve this problem the example would have to be extended to also count the displayed rows and define a top row fraction of for example a minimum of 80% which has to be visible to be reported as the currently visible top row...
Code:
EnableExplicit

#lignes = 12 ; number of lines displayed by the ListView gadget

Enumeration
  #cmd_OK
  #input
  #liste
  #infos_LABEL
  #infos
EndEnumeration

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  ImportC ""
    gtk_tree_view_get_visible_range(*TreeView.GtkTreeView, *StartPath, *EndPath)
  EndImport
CompilerEndIf

Procedure.I GetVisibleTopRow(ListIconID.I)
  Protected VisibleTopRow.I

  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Linux
      Protected *EndPath
      Protected *StartPath

      If gtk_tree_view_get_visible_range(GadgetID(ListIconID), @*StartPath, @*EndPath)
        VisibleTopRow = PeekI(gtk_tree_path_get_indices_(*StartPath))
        gtk_tree_path_free_(*StartPath)
        gtk_tree_path_free_(*EndPath)
      EndIf
    CompilerCase #PB_OS_MacOS
      Protected ContentView.I
      Protected EnclosingScrollView.I
      Protected VisibleRange.NSRange
      Protected VisibleRect.NSRect
     
      ; ----- Get scroll view inside of ListIconGadget
      EnclosingScrollView = CocoaMessage(0, GadgetID(ListIconID), "enclosingScrollView")
     
      If EnclosingScrollView
        ContentView = CocoaMessage(0, EnclosingScrollView, "contentView")
        ; ----- Get visible area
        ;       (automatically subtract horizontal scrollbar if shown)
        CocoaMessage(@VisibleRect, ContentView, "documentVisibleRect")
        ; ----- Subtract border width
        If CocoaMessage(0, EnclosingScrollView, "borderType") > 0
          VisibleRect\size\height - 5
        EndIf
        ; ----- Get visible top row
        CocoaMessage(@VisibleRange, GadgetID(ListIconID), "rowsInRect:@", @VisibleRect)
        VisibleTopRow = Int(VisibleRange\location)
      EndIf
    CompilerCase #PB_OS_Windows
      VisibleTopRow = SendMessage_(GadgetID(ListIconID), #LB_GETTOPINDEX, 0, 0)
  CompilerEndSelect

  ProcedureReturn VisibleTopRow
EndProcedure

If 0 = OpenWindow(0,10,10,300,200,"ListView",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  End
EndIf

ButtonGadget(#cmd_OK,180,175,60,20,"Go to >>>")
StringGadget(#input,244,175,30,20,"50", #PB_String_Numeric)

TextGadget(#infos_LABEL,20,175,48,20,"top item = ")
TextGadget(#infos,20+48+6,175,60,20,"0")

Define lvID = ListViewGadget(#liste,10,10,280,160)

Define i
For i = 0 To 100
  AddGadgetItem(#liste, i, "Ligne "+Str(i))
Next   

Define event, evType, gadget, item
     
Repeat
  event=WaitWindowEvent()

  Select event
    Case #PB_Event_CloseWindow : Break
    Case #PB_Event_Gadget
      gadget = EventGadget()
      Select gadget
        Case #cmd_OK
          i = Val(GetGadgetText(#input))
          SetGadgetState(#liste,i)
          SetGadgetText(#infos,Str(GetVisibleTopRow(#liste)))
        Case #liste
          SetGadgetText(#infos,Str(GetVisibleTopRow(#liste)))
      EndSelect
  EndSelect
ForEver
End

Update: As suggested by Blue (Thank you!), I have replaced
Code:
        Case #liste
          SetGadgetText(#infos,Str(item))
with
Code:
        Case #liste
          SetGadgetText(#infos,Str(GetVisibleTopRow(#liste)))


Last edited by Shardik on Mon Apr 06, 2015 8:48 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: determining item at top of Listview gadget
PostPosted: Mon Apr 06, 2015 1:38 am 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Fri Oct 06, 2006 4:41 am
Posts: 648
Location: Canada
Thank you Shardisk.
I know very well your list of platform equivalent solutions, as i've spent quite a bit of interesting time jumping through the many links you provide. I hope you keep adding to that precious list. It's a major time-saver and headache reliever.

Plus, of course, you're right.
Absent a PB-only solution, nothing is lost. That's the beauty of PB.
If one knows the equivalent platform-specific system calls, CompilerIf..CompilerEndIf switches will do the job very nicely. And, come to think of it, the solutions you offer are, very much a PB-only solutions, but in a broader sense.

So this post is not to imply that there is no salvation if basic-language commands don't provide the answer. It's just that this is what i'm out fishing for. 8)

Many thanks for the code you provided.
Now all I've got to do to fully enjoy your contribution is to scrape together a few thousand dollars to buy myself the Mac of my dreams... :)
Next week maybe... :|

PS: an important element is missing from the last Case in the code you modified :
Code:
SetGadgetText(#infos,Str(item))
; should be replaced by
SetGadgetText(#infos,Str(GetVisibleTopRow(#liste)))

   

_________________
"That's not a bug..." said the programmer. "...It's a feature! "
"Oh! I see..." replied the blind man.


Top
 Profile  
Reply with quote  
 Post subject: Re: determining item at top of Listview gadget
PostPosted: Mon Apr 06, 2015 2:07 am 
Offline
Addict
Addict

Joined: Sun Apr 12, 2009 6:27 am
Posts: 3185
Just select any item after scrolling
With keyboard it will be easier
Tested only with Windows
Still using Shardik code(API for Windows\Linux\Mac) is # 1

Code:
Procedure GetIndex()
  Sel = GetGadgetState(0)
  For index = Sel To 0 Step -1
      SetGadgetState(0,index)
      StartDrawing(WindowOutput(0))
        Color = Point(GadgetX(0,#PB_Gadget_WindowCoordinate)+GadgetWidth(0)-20, GadgetY(0,#PB_Gadget_WindowCoordinate)+2)
      StopDrawing()
      If Color <> GetGadgetColor(0,#PB_Gadget_BackColor)
         Debug index
         Break
      EndIf
  Next
  SetGadgetState(0,Sel)
EndProcedure 
 
OpenWindow(0, 0, 0, 270, 140, "ListViewGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ListViewGadget(0, 10, 10, 250, 120)
  For a = 0 To 20
    AddGadgetItem (0, -1, "Item " + Str(a) + " of the Listview")
  Next
 SetGadgetState(0,0)
 SetGadgetColor(0,#PB_Gadget_BackColor,$FEFEFE)
 SetActiveGadget(0)
Repeat           
  Select WaitWindowEvent()     
      Case #PB_Event_CloseWindow
            Quit = 1
     
      Case #PB_Event_Gadget
          Select EventGadget()
           Case 0
                GetIndex()
           
          EndSelect
  EndSelect
Until Quit = 1
End

_________________
Egypt my love


Top
 Profile  
Reply with quote  
 Post subject: Re: determining item at top of Listview gadget
PostPosted: Mon Apr 06, 2015 3:05 am 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Fri Oct 06, 2006 4:41 am
Posts: 648
Location: Canada
Yesssssss !
That's what i'm talking about.

And quite the clever solution, RASHAD ! :shock:
Nice thinking outside the box.

I like your solution for its originality, its accuracy and its cleverness.
But does it ever flicker ! :(
Another limitation : it can't report the item on the top line if the selected item is not in the viewport of the Listview.

Stop the flicker, and i'll mail you the chocolate medal.
Hurry up before it's fully melted... :wink:

_________________
"That's not a bug..." said the programmer. "...It's a feature! "
"Oh! I see..." replied the blind man.


Top
 Profile  
Reply with quote  
 Post subject: Re: determining item at top of Listview gadget
PostPosted: Mon Apr 06, 2015 3:36 am 
Offline
Addict
Addict

Joined: Sun Apr 12, 2009 6:27 am
Posts: 3185
For the first req.
You must initiate the gadget after selecting unseen item
Code:
Procedure GetIndex() 
  Sel = GetGadgetState(0) 
  For index = Sel To 0 Step -1
      SetGadgetState(0,index)
      StartDrawing(WindowOutput(0))
        Color = Point(GadgetX(0,#PB_Gadget_WindowCoordinate)+GadgetWidth(0)-20, GadgetY(0,#PB_Gadget_WindowCoordinate)+2)
      StopDrawing()
      If Color <> GetGadgetColor(0,#PB_Gadget_BackColor)
         Debug index
         Break
      EndIf
  Next
  SetGadgetState(0,Sel)
EndProcedure 
 
OpenWindow(0, 0, 0, 270, 200, "ListViewGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ListViewGadget(0, 10, 10, 250, 120)
  ButtonGadget(1,10,170,60,20,"TEST")
  For a = 0 To 20
    AddGadgetItem (0, -1, "Item " + Str(a) + " of the Listview")
  Next
 SetGadgetState(0,0)
 SetGadgetColor(0,#PB_Gadget_BackColor,$FEFEFE)
 SetActiveGadget(0)
Repeat           
  Select WaitWindowEvent()     
      Case #PB_Event_CloseWindow
            Quit = 1
     
      Case #PB_Event_Gadget
          Select EventGadget()
           Case 0
                GetIndex()
               
           Case 1
                 SetGadgetState(0,15)
                 GetIndex()
           
          EndSelect
  EndSelect
Until Quit = 1
End


I will try today to fix the flicker(If I can :P )

_________________
Egypt my love


Top
 Profile  
Reply with quote  
 Post subject: Re: determining item at top of Listview gadget
PostPosted: Mon Apr 06, 2015 3:44 am 
Offline
Addict
Addict

Joined: Mon Feb 16, 2015 2:49 pm
Posts: 1711
Don't forget that SetGadgetColor(0,#PB_Gadget_BackColor,$FEFEFE) will clash with other color schemes that the user may have set for their computer.


Top
 Profile  
Reply with quote  
 Post subject: Re: determining item at top of Listview gadget
PostPosted: Mon Apr 06, 2015 3:51 am 
Offline
Addict
Addict

Joined: Sun Apr 12, 2009 6:27 am
Posts: 3185
Hi Dude
No you can select any color you like as long as it is not the default color(-1)
or the highlight selection color

_________________
Egypt my love


Top
 Profile  
Reply with quote  
 Post subject: Re: determining item at top of Listview gadget
PostPosted: Mon Apr 06, 2015 3:55 am 
Offline
Addict
Addict
User avatar

Joined: Sat Apr 26, 2003 8:26 am
Posts: 2916
Location: Planet Earth
I can't see any difference of RASHAD's code to:
Code:
Debug GetGadgetState(0)

That's all it does. It returns the selected item, not the top index.

EDIT:
When changing
Code:
        Color = Point(GadgetX(0,#PB_Gadget_WindowCoordinate)+GadgetWidth(0)-20, GadgetY(0,#PB_Gadget_WindowCoordinate)+2)
to
Code:
        Color = Point(GadgetX(0,#PB_Gadget_WindowCoordinate)+GadgetWidth(0)-30, GadgetY(0,#PB_Gadget_WindowCoordinate)+2)
it works on my Windows 8.1. ( GadgetWidth(0)-30 instead GadgetWidth(0)-20 )

Oh well... :lol: :lol:


Top
 Profile  
Reply with quote  
 Post subject: Re: determining item at top of Listview gadget
PostPosted: Mon Apr 06, 2015 4:20 am 
Offline
Addict
Addict

Joined: Mon Feb 16, 2015 2:49 pm
Posts: 1711
Danilo wrote:
I can't see any difference of RASHAD's code to:
Code:
Debug GetGadgetState(0)

That's all it does. It returns the selected item, not the top index.

That's what I first thought, too, but that's not the request. The OP wants to get the top visible item in the list, not the first item in the list. GetGadgetState(0) doesn't do that.


Top
 Profile  
Reply with quote  
 Post subject: Re: determining item at top of Listview gadget
PostPosted: Mon Apr 06, 2015 4:35 am 
Offline
Addict
Addict
User avatar

Joined: Sat Apr 26, 2003 8:26 am
Posts: 2916
Location: Planet Earth
Dude wrote:
The OP wants to get the top visible item in the list, not the first item in the list. GetGadgetState(0) doesn't do that.

I know what the OP wants, and it was already answered by Shardik.

RASHAD's kludge did not work here (before my small correction), so I didn't see any difference to a simple GetGadgetState(0).


Top
 Profile  
Reply with quote  
 Post subject: Re: determining item at top of Listview gadget
PostPosted: Mon Apr 06, 2015 4:50 am 
Offline
Addict
Addict

Joined: Mon Feb 16, 2015 2:49 pm
Posts: 1711
Danilo wrote:
I know what the OP wants

Sorry Danilo, I didn't realise that. I misunderstood what you were saying.


Top
 Profile  
Reply with quote  
 Post subject: Re: determining item at top of Listview gadget
PostPosted: Mon Apr 06, 2015 6:21 am 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Fri Oct 06, 2006 4:41 am
Posts: 648
Location: Canada
Danilo wrote:
I can't see any difference of RASHAD's code to:
Code:
Debug GetGadgetState(0)

That's all it does. It returns the selected item, not the top index.

Oh well... :lol: :lol:

Hi Danilo
.
Rashad's solution (or kludge as you call it) works as long as there's a selected line in the viewport of the gadget. Run the code in the initial message of this post to better see what I'm looking for. That code does exactly what i want, but of course it uses an API call, which is cheating since the objective is to do it without any API call. That may not be totally possible (although Rashad may prove me wrong!) and you may wonder "but WHY bother?".
It's just curiosity : i spent a long time trying to get that done, and got frustrated that i couldn't. So i figured i'd ask others if they had better luck, or ideas, or skills.

So far, Rashad's code is the closest, as it solves part of the problem. And you've got to admit, kludge or not, his approach is clever...

Rashad's original code (with the (-20) displacement) worked on my 8.1 machine as is.
I'm just wondering why, on yours, the testing point had to be moved another 10 pixels back...
But that made me realize that his code may not provide the expected cross-platform result after all, since other systems surely don't draw Listview gadgets the same way Windows does.


   

_________________
"That's not a bug..." said the programmer. "...It's a feature! "
"Oh! I see..." replied the blind man.


Top
 Profile  
Reply with quote  
 Post subject: Re: determining item at top of Listview gadget
PostPosted: Mon Apr 06, 2015 7:39 am 
Offline
Addict
Addict
User avatar

Joined: Sat Apr 26, 2003 8:26 am
Posts: 2916
Location: Planet Earth
Blue wrote:
Rashad's original code (with the (-20) displacement) worked on my 8.1 machine as is.
I'm just wondering why, on yours, the testing point had to be moved another 10 pixels back...
But that made me realize that his code may not provide the expected cross-platform result after all, since other systems surely don't draw Listview gadgets the same way Windows does.

The vertical scrollbar width may be different between OS, and different between system DPI settings.

Code:
Debug GetSystemMetrics_(#SM_CXVSCROLL)
Outputs 21 with my 125% DPI setting (2560x1440 @ 27"). When switching to 100% DPI, it returns 17 here.
Of course, that's completely different on other configurations and OS. '-24' works for me (21 + 2 px border + 1).

Just make sure the pixel you check is never part of a character, and always the gadget background vs. selection (depends on system, text length, (system) fonts, DPI settings, gadget borders, etc.)
In my personal opinion that way is not reliable, but of course you can use what you like...

Anyway... ;)


Top
 Profile  
Reply with quote  
 Post subject: Re: determining item at top of Listview gadget
PostPosted: Mon Apr 06, 2015 8:40 am 
Offline
Addict
Addict
User avatar

Joined: Thu Apr 21, 2005 2:38 pm
Posts: 1581
Location: Germany
I have always been an admirer of RASHAD's creative solutions but unfortunately they are rarely usable for cross-platform solutions even if they should work when utilizing only native PB functions. RASHAD's current example simply can't work in MacOS because it seems not possible to use Point() in MacOS for reading the color of a pixel in a Gadget. Point() always returns 0 independant of its position in the ListViewGadget...


Top
 Profile  
Reply with quote  
 Post subject: Re: determining item at top of Listview gadget
PostPosted: Mon Apr 06, 2015 11:58 am 
Offline
Addict
Addict

Joined: Sun Sep 07, 2008 12:45 pm
Posts: 4058
Location: Germany
Hi,

for performnace reasons:
Put the StartDrawing() and StopDrawing() outside of the for next loop.

Bernd


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 29 posts ]  Go to page 1, 2  Next

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 15 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye