Standardize Color Handling #11
Labels
No Label
Alpha Release Requirement
Bugfix
Demo Target
Documentation
Major Feature
Minor Feature
Refactoring & Cleanup
Tiny Feature
No Milestone
No project
No Assignees
1 Participants
Notifications
Total Time Spent: 10 hours 16 minutes
Due Date
john
10 hours 16 minutes
No due date set.
Dependencies
No dependencies set.
Reference: john/McRogueFace#11
Loading…
Reference in New Issue
No description provided.
Delete Branch "%!s(<nil>)"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
notes say:
15 refactor: standardize color handling: 3- or 4-tuple, 3 or 4 member lists, any mix of ints or floats (standardized to 0 - 255); or color object
This issue is for the method to take a PyObject* and return a correctly assembled mcrfpy.Color (maybe a sfml.Color later on, if there's a suitable SFML Python implementation that can be shipped with McRogueFace)
Once it's available, every widget that uses color (Frame, Caption, Grid, GridPoint) should have their versions replaced
Fix Color Handlingto Standardize Color HandlingPyColor
This type has some other requirements that make it differ from PyTexture:
So what should a PyColor actually hold?
a pointer to a sf::Color, a weak_ptr to a UIDrawable, and an enum for the particular color it targets.
std::shared_ptr<std::vector<std::shared_ptr<UIDrawable>>> ui_elements;
therefore UIDrawable can inherit from
enable_shared_from_this
and always provide ashared_ptr
to the UIDrawableThere will also be some confusing behavior in terms of assignment -
setattr
on the Python types of the objects. Those "color figure-outer" methods should be static methods in the newPyColor
. After building aPyColor
linked togrid_point
'sbackground_color
attribute, we can call "set(args)
" to use the pointer and update the value.This will never work, it simply overwrites the value of
c
. We can givec
as much behavior as we want to make it convenient and have a link to the background color, but the=
operator can't be overwritten.This will work - the color pointer can be modified, which edits the grid point. If you held on to
c
longer thangrid_point
's lifetime, we can safely raise a Python exception.Does the new PyColor need
shared_from_this()
? Seemingly not - it doesn't load its own data into a shared_ptr to send as a Python object.Got a bit distracted, but I was having fun. I wanted to give colors readable names and also have an absurd number of plain text names that could be used.
Basically took CSS color codes, the XKCD color survey, and a wikipedia article on crayons' colors and made a list of 1,258 named colors. I initially wanted to do compile-time processing in a C++ file to generate a table including the values needed to make the "nearest name" test for a given RGB value just a single simple subtraction.
Yes, the whole point of this thing is to take any RGB value and give it a name.
This is an unfinished feature, but the goal output for this script is a C++ file - it'll give the RGB code and color name in a single static array, sorted by palette priority then by "voronoi radius" (to reduce average lookup time) so that the first result in the list is the correct answer.
See
2cac6f03c6
for initial scribbles for the PyColor class; see3728e5fcc8
for the color mapping codeSome quick thoughts on
13a4ddf41b
I'm honestly not feeling great about how this feature is going - the time spent is getting out of hand, and the PyColor class is huge. There are three modes to it. I have a sinking feeling that this thing is going to get gutted before the issue gets closed.
sf::Color*
and delete it on cleanup. So newPyColorObject
s /PyColor
s need to drop fromSELF_OWNED
toBORROWED
so they don't free the reference they borrowed from. But if the original gets cleaned up first, it'll segfault the next time the child gets accessed. So this "self owned" method should never be used from Python, and there's no standalone color container functionality.The main reason for all this bloat is because I wanted colors that were linked to a parent's property. So I built it around a pointer, but the truth is most UIDrawable objects use SFML getters/setters to change color values. So I tacked that on too - function pointers.
So to streamline this thing as I try to get it across the finish line:
_PyColorData
struct didn't help the complexity of the class - it probably hurt it. I broke the pattern of the Python object storing a shared pointer to the C++ object, so now I'm doing witchcraft with static methods to create aPyColor
using aPyColorObject
's data contents. I think I can say for sure that I don't like how it looks right now.almost 300 lines in PyColor's files - I bet it can be done nicely in 200 lines.
41509dfe96
- PyLinkedColor initial versionPyLinkedColor
is my answer to the thoughts from last night. I'm going to un-refactorPyColor
to have no frills, just a simple sf::Color instance to copy by value. The linked variant uses set() and get() to call functions.Sure enough:
But I've hit an architectural snag:
I can't pass
UIDrawable.some_sfml_member.getFillColor
as the function pointer.However, PyLinkedColor already requires a weak_ptr to its parent, and an integer index.
So the solution to color linking seems to require:
sf::Color getColor(int)
andvoid setColor(int, sf::Color)
.static void UIDrawable::getColor(UIDrawable&, int)
andstatic sf::Color UIDrawable::setColor(UIDrawable&, int, sf::Color)
__repr__
, but I'll probably settle for hand-copying it now.Let's talk about
06e24a1b27
so I did not do what I said I would do last night. Instead of building a workaround for function pointers, I dusted off the technique I used to pull off animations, and upgrade
PyLinkedColor
to usestd::function
. I form a closure over the shared_ptr to the UIDrawable derived object, then wrap whatever get/set color code (for a property or a SFML member object method) to pass get and set to the linked color object.Let's try and close this up:
3991ac13d6
All three of these have had significant motion, but I need to chase down a segfault before this stuff can get cleaned up for merge
OK, we made it!
Ultimately, I have decided to abandon PyLinkedColor for now. After reflecting on the use cases, and looking ahead to doing the same thing to the Vector class, I did not have much interest in actually including the feature. I learned a bit more about lambdas and std::function, but sincerely it was an ADHD brain side-quest. Probably tripled the necessary time required to complete this feature.
Note: The segfaults were caused by not calling
Py_INCREF
on a new reference; the result is thatprint(c.fill_color)
would segfault whilecolor = c.fill_color
would not. I think_
might have been accessing the null pointer.Some cleanup actions are definitely being deferred, but I want to take the win now. It's my project, I can do that