{"id":51480617,"url":"https://github.com/akdevbox/wypeditor","last_synced_at":"2026-07-07T01:30:21.023Z","repository":{"id":334375678,"uuid":"1010882509","full_name":"akdevbox/wypeditor","owner":"akdevbox","description":null,"archived":false,"fork":false,"pushed_at":"2026-01-24T10:36:20.000Z","size":718,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-24T21:27:30.065Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/akdevbox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-30T01:30:05.000Z","updated_at":"2026-01-24T10:36:24.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/akdevbox/wypeditor","commit_stats":null,"previous_names":["akdevbox/wypeditor"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/akdevbox/wypeditor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akdevbox%2Fwypeditor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akdevbox%2Fwypeditor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akdevbox%2Fwypeditor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akdevbox%2Fwypeditor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/akdevbox","download_url":"https://codeload.github.com/akdevbox/wypeditor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akdevbox%2Fwypeditor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35211553,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-06T02:00:07.184Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-07T01:30:16.839Z","updated_at":"2026-07-07T01:30:20.809Z","avatar_url":"https://github.com/akdevbox.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NOTICE\nThis is an old and unmaintained project of mine, I've uploaded it to GitHub for preservation and archiving.\n\n# A Proof of Concept Image Editor (pygame)\n\nThe following image editor is made using pygame and a custom GUI\nlibrary under the hood. The GUI library takes some inspiration from\nflutter. The layout calculation part of the GUI library has been separated\ninto its own module. \n\n**Update: The GUI library has been separated from this project into its own library named wyper**\n\nThe Image editor comes with the following features:\n\n* Automatic Dark/Light mode depending on your system settings.\n* Fractional DPI Scaling GUI for crystel clear interface on even high DPI monitors\n* Resizable Layout\n* Interactive Image Cropping Functionality\n\n\n![](scrshots/mainwindow.png)\n\n### How it works\n\nThe gui component of this program is completely reusable and can be used to create other GUI applications. Please look at wyper library for reference.\n\nWidgets are easy to create with only a few methods needed to be overriden.\n\nWidgets at bare minimum need to provide `__init__` method and `render` method. Widgets if need be can change their own layoutobject as they see fit. The `after_layout_recalculation` method should be overriden if you need to preprocess or draw something after the layout is calculated. The calculated layout is stored in `self.layoutobject.rendered`.\n\nSubclasses of `Widget` such as `WidgetWithChild` and `WidgetWithChildren` are also available for some extra methods. Other widgets can also be overriden to make changes.\n\nLayoutObjects are used for layout positioning, sizing and calculations. These LayoutObject come in the following variations:\n\n1. LayoutObject - A single layoutobject for widgets without children\n\n2. LayoutObjectList - A single layoutobject that can have multiple children. These children can be any of the listed LayoutObject including list itself. Widgets such as Column, Row derive from this\n\n3. LayoutObjectStack - A sinlge layoutobject that can have multiple children stacked on top of each other. The layoutobject does not care about overlapping and simply provides the widgets with overlay capabilities\n\nThe 2 and 3 type objects also have properties such as mainAxisAlignment and crossAxisAlignment. \n\nEach LayoutObject can be sized with the folowing possible units.\n\n1. `LayoutUnit.ABSOLUTE` - This is the most basic unit and says that the size of the child is fixed\n\n2. `LayoutUnit.PERCENTAGE` - This unit takes a percentage amount of space from the parent. A little quirk about this is that the percentages are calculated after absolute sized widgets have been allocated. Hence a 100% sized widget will occupy 100% of remaining space instead of parent space\n\n3. `LayoutUnit.FLEX` - This unit is for distributing leftover space proportionally. Simply put, the values with this unit are proportions that the leftover space is to be distributed in after calculations for 1 and 2 type units is complete.\n\nto calculate a tree of layout. Call the `calculate(spacex, spacey, offset)` on the parent method. The spacex is space available in x-axis and same is for spacey. Offset defines how the widgets are to be initally placed from reference. Offset for parent widget is usually set to `(0, 0)`.\n\nHere is how the parent layoutobject for this image editor looks like:\n\n```\nLayoutObjectStack[x0, y0, w1000, h625\n    LayoutObjectList[x0, y0, w1000, h625\n        LayoutObjectList[x0, y0, w1000, h37\n            LayoutObject[x0, y0, w154, h37],\n            LayoutObject[x154, y0, w3, h37],\n            LayoutObject[x157, y0, w85, h37],\n            LayoutObject[x242, y0, w3, h37],\n            LayoutObject[x245, y0, w114, h37],\n        ],\n        LayoutObjectList[x0, y37, w1000, h567\n            LayoutObject[x0, y37, w12, h0],\n            LayoutObjectStack[x12, y37, w682, h567\n                LayoutObjectStack[x12, y37, w682, h567\n                    LayoutObject[x12, y37, w682, h567],\n                ],\n                LayoutObjectStack[x171, y268, w364, h105\n                    LayoutObject[x171, y268, w364, h105],\n                ],\n            ],\n            LayoutObject[x694, y37, w12, h0],\n            LayoutObject[x706, y37, w3, h567],\n            LayoutObjectList[x709, y37, w291, h567\n                LayoutObject[x854, y37, w0, h10],\n                LayoutObjectList[x709, y47, w291, h50\n                    LayoutObject[x709, y47, w10, h0],\n                    LayoutObject[x719, y47, w271, h50],\n                    LayoutObject[x990, y47, w10, h0],\n                ],\n                LayoutObject[x854, y97, w0, h10],\n                LayoutObject[x709, y107, w291, h3],\n                LayoutObject[x854, y110, w0, h10],\n                LayoutObject[x816, y120, w76, h33],\n                LayoutObject[x854, y153, w0, h5],\n                LayoutObjectList[x709, y158, w291, h50\n                    LayoutObject[x709, y183, w8, h0],\n                    LayoutObject[x717, y158, w88, h50],\n                    LayoutObject[x805, y183, w16, h0],\n                    LayoutObject[x821, y177, w171, h12],\n                    LayoutObject[x992, y183, w8, h0],\n                ],\n            ],\n        ],\n        LayoutObject[x0, y604, w1000, h21],\n        LayoutObjectList[x0, y625, w0, h0],\n    ],\n]\n```\n\nAs you can see, the calculated layout is stored as rectangles with x, y, width, height.\n\nInternally, the widgets use the `_scale(int) -\u003e int` function to scale the UI according system DPI scaling. All this works thanks to `BuildContext()` object which implements a singleton class. This class can only have a single instance throughout the thread and hence this is used to save state information and is used to cache font sizes.\n\nSince the pygame library is used internally to draw the pixels. Anti Aliasing is done to prevent pixelated looks. This in turn has the effect of working with workarounds to anti alias shapes that do not have an anti aliasing methods.\n\nUnder the hood, this application uses the widget `PILImageView` to convert PIL (Pillow) library images to viewable pygame surfaces. The actual image processing is done on the Pillow Image itself.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakdevbox%2Fwypeditor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fakdevbox%2Fwypeditor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakdevbox%2Fwypeditor/lists"}