New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend ImageMap to Canvas #447

Closed
natfast opened this Issue Apr 30, 2018 · 7 comments

Comments

Projects
None yet
2 participants
@natfast

natfast commented Apr 30, 2018

It would be nice if ImageMap could also function on Canvas widgets, rather than only Image widgets.

@jarvisteach

This comment has been minimized.

Owner

jarvisteach commented May 1, 2018

The ImageMap is actually quite a simple piece of code.

You could create one on a canvas with very little effort:

def click(event): print(event.x, event.y)

with gui("Canvas Click", "400x400") as app:
    app.addCanvas("c1").bind("<Button-1>", click)

Then you can have a loop through a set of coordinates, or just a few IF statements to determine where on the canvas was clicked....

@jarvisteach jarvisteach added the question label May 1, 2018

@natfast

This comment has been minimized.

natfast commented May 1, 2018

I actually extended your base. It could probably be optimized, but it works for now.

   # extend image map to include canvas objects
   from appJar import gui

   class Point(object):
       def __init__(self, x=0, y=0):
           self.x = x
           self.y = y

       def __str__(self):
           return "({},{})".format(self.x, self.y)
    
   class CMRectangle(object):
       def __init__(self, name, posn, w, h):
           self.name = name
           self.corner = posn
           self.width = w
           self.height = h

       def __str__(self):
           return "{3}:({0},{1},{2})".format(self.corner, self.width, self.height, self.name)

       def contains(self, point):
           return (self.corner.x <= point.x <= self.corner.x + self.width and
                       self.corner.y <= point.y <= self.corner.y + self.height)
        
   class CanvasMap(gui):
       def __init__(self, title, **kwargs ):
           super().__init__()

        
    # function to configure a canvas map
       def setCanvasMap(self, name, func, coords):
           img = self.widgetManager.get(self.Widgets.Canvas, name)

           rectangles = []
           if len(coords) > 0:
               for k, v in coords.items():
                   rect = CMRectangle(k, Point(v[0], v[1]), v[2]-v[0], v[3]-v[1])
                   rectangles.append(rect)

           img.MAP_COORDS = rectangles
           img.MAP_FUNC = func
           img.bind("<ButtonRelease-1>", lambda e: self._canvasMap(name, e), add="+")

       # function called when a canvas map is clicked
       def _canvasMap(self, name, event):
           img = self.widgetManager.get(self.Widgets.Canvas, name)
           for rect in img.MAP_COORDS:
               if rect.contains(Point(event.x, event.y)):
                   img.MAP_FUNC(rect.name)
                   return "break"

           img.MAP_FUNC("UNKNOWN: " + str(event.x) + ", " + str(event.y))

@natfast

This comment has been minimized.

natfast commented May 1, 2018

Also, I changed the mouse event to release, as I was getting several down events on a single click, but only one up event. I don't plan on supporting dragging with this function.

@jarvisteach

This comment has been minimized.

Owner

jarvisteach commented May 1, 2018

I like it!

I think I might look at refactoring my code, so that the functions I use are more generic and can more easily be reused. I'll also update the init.py file, so that it's easier to import the rectangle & point classes...

jarvisteach added a commit that referenced this issue May 1, 2018

@natfast

This comment has been minimized.

natfast commented May 1, 2018

Thanks.

And BTW I am having a great time working with your framework. It really makes UI development relatively painless.

Would like to see more of those generic types of functions, like you are considering in your refactoring.

Having to qualify the specific widget (Entry, SpinBox, ListBox (List?)...) in a modifier like app.enableEntryTooltip(control) is a bit heavy handed. Since you know all the widgets by control name and their types, you should be able to apply that without a specific widget qualifier. app.enableTooltip(control) should be sufficient.

On the other hand, having to list out the widget type prevents confusion in coding and enhances the awareness of functional capabilities for your students.

I guess another way to approach it might be
app.enableTooltip( ) app.enableTooltip("Entry:Start Now")

The world is your oyster.

Keep up the good work!

@jarvisteach

This comment has been minimized.

Owner

jarvisteach commented May 7, 2018

@natfast - that's one of the new features (sort of) - you can now set lots of properties on the new functions. So:

app.entry("name", tip="helpful tooltip", submit="press")

jarvisteach added a commit that referenced this issue May 7, 2018

Refactored image maps #447
ImageMap code now generic. Is also used by canvases.

@jarvisteach jarvisteach added this to the 1.0 milestone May 7, 2018

@jarvisteach

This comment has been minimized.

Owner

jarvisteach commented May 7, 2018

I've now included imageMaps in the canvas.

You can call .setCanvasMap() or pass a submit & map parameter when you call .canvas()

@jarvisteach jarvisteach closed this May 7, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment