-
Notifications
You must be signed in to change notification settings - Fork 21
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
GdiGraphics and ThemeManager API extensions and fixes #147
base: master
Are you sure you want to change the base?
GdiGraphics and ThemeManager API extensions and fixes #147
Conversation
Thanks for the PR! One thing though, alphabetic sorting of the methods is a conscious design choice, so, please, don't reorder methods :) |
…nd added GdiGraphics support for nested containers.
Ouch! slaps forehead I should've seen that pattern, …instead I just assumed the methods were in implementation order. And while at it, I've also reverted the change regarding the font size in And finally, added functions for saving and restoring the graphics object's state, and support for nested container, which could come in handy when drawing hierarchical ui-s ( https://docs.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-using-graphics-containers-use ), and added support for the GetDpiX and GetDpiY methods provided by the |
…/transform from GDI+ to GDI
Have yet to check the main stuff, but |
I know less than nothing about any of it but I can tell you the DT_CALCRECT stuff copied from GdiDrawText to DrawThemeText flat out doesn't work (I tested the appveyor build). You probably want to use GetThemeTextExtent. https://docs.microsoft.com/en-us/windows/win32/api/uxtheme/nf-uxtheme-getthemetextextent Also, the font weight is heavier than expected. Exposing GetThemeColour is a great idea though - I already stole that. |
@TheQwertiest: @marc2k3: Since then I've been toying with things like patching the createhwnd() trough to javascript so custom WS_POPUP controls (like foo_osd, but scripted) could be made (with the same onpaint callback, but passing a different GdiGraphics, while maybe having to register an extra js callback for the parts of wndproc that cannot be generalized from the c++ side ), or god forbid, comctrl32 controls with native win32 api, but i havent got much mileage in this direction, other than it shoud be theoretically very possible (even more so with the utils.GetSysMetric calls, which allow one to query the virtual desktop rect, etc), but since my few weeks off work ended, and I got back to my day job i haven't got that much time to experiment. I did however hack together something which , for now at least, i'd rather share just as an attachment here: and contains some a v0 basic ui, a half rewritten v1, some demo/test scripts, a gross hack tag normalizer (uhh, dont ask, but could be useful if i refactor it sometime), and an utility that uses ArrayBuffers to decode TRAKTOR4 tags in mp3&flacs... Apart from that it also contains some ES6 style class definitions of the Wshell, FSO, Shell.Application, Adodb.Stream ActiveXobjects (in /lib/api/...), and some win32/gdi api related flag/enum/const ones at (/lib/gui/winapi/...), (mostly an extension of Flags.js with theme / themeprop data, and some extra enums) that could be considered useful for reference / documentation / intellisense purposes. |
@razielanarki I understand your scenario, but what I mean is that |
…e_manager_api_extensions_and_fixes
…and other misc. minor tweaks
Hi again!So i've been hacking away at the code slowly since, fixing stuff and add some more serious/useful features. like: Win7 and GDI compatible
|
- uses a `std::default_delete` specialization - allows assigning "related" `std::shared_ptr<unique_gdi_handle<H>::element_type>` and their `::weak_type`-s from an `unique_gdi_handle<H>` while copying the deleter the latter allows to remove the dependeny n WIL in the GdiFont HFONT cache
3ba55f3
to
d904691
Compare
Hi @razielanarki, I see you try to give TheQwertiest another hand and help in SMP development which is great! I take this chance to contact you in hope you can fix some bugs/crashes in SMP when using Wine under Linux. If you want you can contact me in private here: It would be the best to also contact WilB and work with him together to fix these issues, here is his contact: You can send WilB my greetings and also from paregistrase. I know TheQwertiest is pretty busy with other things, so I gave it a shot to contact you since I saw your pretty Thank you! -TT |
Hi, thank you for the kinds words @TT-ReBORN ! Heh, i usually think this of this as just some hacking away at some mildly useful graphics related parts, while trying to get a deeper understanding of the codebase as a whole (and i mean just the smp codebase, but also reading heavily into/trying to wrap my head around related projects), and catching up on my far-left-behind-while-being-a-fullstack-webdev-guy c++ skills, which i haven't really used since,.. like the first versions of openttd... (and before that i hacked mostly in standard c -- doom/q1), so yeah, i have a lot to catch up on yet. (and i have a few pet projects/hacks in smp/foobar i still aim to cobble together) all that said, i might try to look at some of the bugs you mentioned, but i cant promise anything ... windows is a complex system, with layers upon layers of legacy code some parts of which are virtually unchanged since the win3.11 days.. (because "the customers need their apps working" motto) and i can only really admire the determination of the wine/reactos guys to try to replicate it, or even better: its like changing the whole car from a ford-T to a ferrari under, leaving the dashboard and steering, and most parts of the passenger cabin intact in tiny detail, while also making everything a part of the "new". ("The Old New Thing" is a very exact phrase to describe it, and its the title for a favorite of mine developer blog from one of the guys who has seen it (windows) through all) and while i'm there, writing this thank you, in a very long winded post...:), i wanted to ask @TheQwertiest , if i may: do you know any online mirrors, or such, for the (sadly taken down) MDN version of spidermonkey docs (save building it for myself ...but how..must be some docs/notes somewhere)? (spidermokey.dev is just -- doesnt cut it) and again thanks @TT-ReBORN ! i might make myself useful! (makes zoidberg noises) :) |
Hi @razielanarki, thanks for your answer and hope in fixing the bugs/crashes =). I wanted to release Georgia-ReBORN crash free for the first public release, these issues are old and already documented multiple times in the HydrogenAudio forums ( WilB's biography and library thread ) by Linux users... If this does help you, here is an answer from WilB about fetching images in his biography script: "RE: downloading images I did put some console traces in the web.js I sent you to check this. Below is what you sent me. You can see that artist photo links were correctly extracted. However, presumably they didn't save. The save process streams the image with windows cscript that's run through ActiveXObject('WScript.Shell'), so I expect it's failing there: I couldn't see anything I could change in that. I also had a quick look for an alternative method to save images but drew a blank, unless you can come up with something. In due course SMP may get updated with modern web-look-up methods that don't use ActiveXObject & so image saving may become much easier." He also tell me that the right click is related to the copy function and suggested me to comment out "doc.parentWindow.clipboardData.getData". This disable copy and paste but lets you use the right click. So seems to be necessary a change in the SMP's author side in order to make this feature works. Let's see if we can also get a conversation going on with @Wil-B. Thank you very much for trying! -TT |
I can confirm on Artix (Linux) with latest stable WINE x86 in Appimage. |
Regarding saving images, as noted above, the first part of the process is to call windows cscript that's run through ActiveXObject('WScript.Shell'). This in turn calls an external .vbs file that streams and saves the images. To do this, the .vbs file uses a number of further objects:
I guess as these are in an external file they're normally run by windows & may be independent of SMP. I think it would need someone with coding skills running Linux (which I don't have & so can't test anything) to debug exactly where it's failing and to see if it's possible to work around it. Otherwise SMP may need to be updated with new methods. Right-click error is due to: doc.parentWindow.clipboardData.getData, where doc is ActiveXObject('htmlfile'). So the error seems to be due to some issue with that ActiveXObject method in Linux . It's used to paste from clipboard. So another way of accessing the clipboard may be needed, or comment out usage. Options uses the SMP ShowHtmlDialog. ShowHtmlDialog v2 is in SMP current tasks and plans. |
@TT-ReBORN @Wil-B hi!
you can reach me at hyrdogenaudio via: https://hydrogenaud.io/index.php?action=profile;u=142642 (and pkz drop me a msg withthe topic link there, i may just miss is being just that featherheaded and aop sometimes :) TY! ) |
aaaaand i just realized that last time (actually before that) i missed to upload the scripts whitch i used to test the: Directwrite and FontCache / Metrics
|
@razielanarki @TheQwertiest @Wil-B @fwn0 new thread on HydrogenAudio started here: Hi razielanarki, Edit: I have tested it on the latest Wine 6.02 stable . The xml controls you've mentioned is it 6.02 stable or 6.22 dev? Thanks! -TT |
Ok, I'm back for the time being, so I'll at least have a look at what you have accomplished here :) |
the only available docs are in header files of mozjs and in their example repo |
Yeah, it will have to be separated at some point of the time, but we can keep at as is for the time being |
On the subject of gdiplus, the latest windows SDKs (20348 / 22000) have a fix for the min/max issue in gdiplustypes.h meaning this can be nuked from stdafx.h
It only took them about 20 years or something. |
I'm implementing this right now. I posted a little preview here... https://hydrogenaud.io/index.php?topic=110499.msg1007769#msg1007769 |
cool. coolcoolcool :) i've been lurking around and wanted to check out foo_jscript_panel (and the api you've implemented), but the repo seems like it's been archived? :( |
I've essentially ended development on that version because gdi/d2d interop doesn't seem feasible. I was using a DC render target and calling BindDC / BeginDraw / EndDraw on every function call hammered performance (it was fine for 99% of use cases but scrolling a playlist was not nice). Maybe there was an easier solution but I'm working on a new version which nukes all gdi support. Not even sure I'll release it. But I can post a few code snippets of how I implemented that text range.... First the JS... function RGB(r, g, b) {
return (0xff000000 | (r << 16) | (g << 8) | (b));
}
var fonts = utils.ListFonts().toArray();
var text = utils.ReadUTF8("E:\\Applications\\foobar2000\\profile\\js_data\\artists\\Little Scream\\allmusic.The Golden Record.txt");
var arr = text.split(" "); // split text in to whole words for styling
var styles = [];
refresh();
function refresh() {
styles = [];
var start = 0;
arr.forEach(function(item, i) {
styles.push({
start : start,
length : item.length + 1,
font_name : fonts[Math.floor(Math.random() * fonts.length)],
font_size : 12 + Math.floor(Math.random() * 20),
font_weight : Math.round(Math.random() * 800) + 100, // values between 100-900
colour : RGB(Math.random() * 200, Math.random() * 200, Math.random() * 200),
underline : Math.random() < 0.1,
strikethrough : Math.random() < 0.1,
});
start += item.length + 1;
});
}
function on_paint(gr) {
gr.WriteText(text, JSON.stringify(styles), 0, 10, 10, window.Width - 20, window.Height - 20);
}
window.SetInterval(function () {
refresh();
window.Repaint();
}, 500); Then translating the JSON to DWRITE_TEXT_RANGE If the JSON is an object, just apply the style to the whole range. HRESULT JSGraphics::apply_styles(IDWriteTextLayout* text_layout, const std::wstring& styles, uint32_t total_length)
{
json j = json::parse(from_wide(styles), nullptr, false);
if (j.is_object())
{
DWRITE_TEXT_RANGE range(0, total_length);
RETURN_IF_FAILED(apply_style(text_layout, j, range));
}
else if (j.is_array())
{
for (auto&& obj : j)
{
if (!obj.is_object()) return E_INVALIDARG;
auto start = obj["start"];
auto length = obj["length"];
if (!start.is_number_unsigned() || !length.is_number_unsigned()) return E_INVALIDARG;
DWRITE_TEXT_RANGE range(start.get<uint32_t>(), length.get<uint32_t>());
RETURN_IF_FAILED(apply_style(text_layout, obj, range));
}
}
return S_OK;
} then parsing each HRESULT JSGraphics::apply_style(IDWriteTextLayout* text_layout, json j, DWRITE_TEXT_RANGE range)
{
auto font_name = j["font_name"];
if (font_name.is_string())
{
auto tmp = to_wide(font_name.get<std::string>());
RETURN_IF_FAILED(text_layout->SetFontFamilyName(tmp.data(), range));
}
auto font_size = j["font_size"];
if (font_size.is_number_unsigned())
{
auto tmp = to_float(font_size.get<uint32_t>());
RETURN_IF_FAILED(text_layout->SetFontSize(tmp, range));
}
auto font_weight = j["font_weight"];
if (font_weight.is_number_unsigned())
{
auto tmp = static_cast<DWRITE_FONT_WEIGHT>(font_weight.get<uint32_t>());
RETURN_IF_FAILED(text_layout->SetFontWeight(tmp, range));
}
auto font_style = j["font_style"];
if (font_style.is_number_unsigned())
{
auto tmp = static_cast<DWRITE_FONT_STYLE>(font_style.get<uint32_t>());
RETURN_IF_FAILED(text_layout->SetFontStyle(tmp, range));
}
auto font_stretch = j["font_stretch"];
if (font_stretch.is_number_unsigned())
{
auto tmp = static_cast<DWRITE_FONT_STRETCH>(font_stretch.get<uint32_t>());
RETURN_IF_FAILED(text_layout->SetFontStretch(tmp, range));
}
auto strikethrough = j["strikethrough"];
if (strikethrough.is_boolean())
{
auto tmp = strikethrough.get<bool>() ? TRUE : FALSE;
RETURN_IF_FAILED(text_layout->SetStrikethrough(tmp, range));
}
auto underline = j["underline"];
if (underline.is_boolean())
{
auto tmp = underline.get<bool>() ? TRUE : FALSE;
RETURN_IF_FAILED(text_layout->SetUnderline(tmp, range));
}
auto colour = j["colour"];
if (colour.is_number())
{
auto tmp = colour.get<int64_t>();
wil::com_ptr_t<ID2D1SolidColorBrush> brush;
RETURN_IF_FAILED(m_render_target->CreateSolidColorBrush(to_colorf(tmp), &brush));
RETURN_IF_FAILED(text_layout->SetDrawingEffect(brush.get(), range));
}
return S_OK;
} |
neat, thanks! on a (maybe moot point) side note, i believe you should only call BindDC once (maybe bind to a panel HWND sized memory dc via CreateCompatibleDC), and update using gdi blitting (i'm doing something similar in https://github.com/razielanarki/foo_spider_monkey_panel/blob/674a01f006e748a8c8b1bdc1f8a39dccf2b51862/foo_spider_monkey_panel/utils/dwrite_renderer.cpp#L231-L291, however dwrite handles the d2d context for me in the background, but there are functions like https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getboundsrect that can retrieve the changed boundsrect to update back.. i've only stubled upon it when i've implemented the text-bounds-clipped-back-blitting above, lol) in the meantime i've took an ever deeper dive into mozilla codebase to see how they did the js binding via DOM/XPCOM, as i believe there's an solution buried in there somewhere for wrapping+exposing COM apis to JS, cuz i like how neat the .idl definitions are in jscript_panel (not to mention the usefulness for foobar skin developers if a common api could be easily shared between foo_XYZ_scripting_panel implementations). (ps: have you seen microsoft clearscript? too bad it's mostly .net/C# only...) |
Hi!
This "monstre" PR mainly extends the capabilites of the
GdiGraphics
API and theThemeManager
API with the following callbacks (and some other things listed after):GdiGraphics
GetX
counterparts forSetInterpolationMode
,SetSmoothingMode
andSetTextRenderingHint
GetX
/SetX
functions for accessingTextContrast
,CompositingMode
,CompositingQuality
andPixelOffsetMode
onGdiplus::Graphics
objectsGdiDrawText
respects the clipping and transformation setThe changes were made to enable easier implementing of custom UI elements with scrolling contents (using clipping + translate transforms), and other functions were introduced for completeness (getX + setX, and rotate + scale + multiply)
ThemeManager
DrawThemeBackground
respects the clipping and transformation set, and the clipping rectangle specified by theclip_X
parameters is fixedDrawThemeText
function for drawing text using the font and color defined in the theme for the partId and stateId selected, based on the implementation ofGdiGraphics::GdiDrawText
GetThemePropertyOrigin
,GetThemeMetric
,GetThemeBool
,GetThemeInt
,GetThemeColour
,GetThemeMargins
,GetThemePartSize
,GetThemeEnumValue
,GetThemeBackgroundContentRect
GetThemeSysInt
,GetThemeSysSize
,GetThemeSysColour
GdiFont
object, and one variant returning thefontName
,fontSize
andfontStyle
arguments as an array:GetThemeFont
,GetThemeFontArgs
,GetThemeSysFont
,GetThemeSysFontArgs
The changes were made to extend the functionality when implementing themed controls, developers now can use the fonts and colors defined in the theme, and set control sizes and margins according to the theme.
Other changes and fixes
GdiGraphics
andThemeManager
classes have been largely refactored, mainly the order of the functions changed, and topically grouped together.Also, some variable and parameter names were changed. The types and order of variables and parameter WERE NOT changed.
foo_spider_monkey_panel.js
file has been updated with the new API (not sure about how to update the html docs properly)GdiFont::Constructor
: previously when creating aGdiFont
instance from anon_paint
callback, aGdiDrawText
call following in the same callback didn't draw anything (and didn't throw an error).Now the text is drawn correctly.
Important changes
(I will submit a small PR to
fb2k_utils
too)edit: the PR is at: Add an option to enable suppression of the error popup fb2k_utils#1
fontSize
in the aforementionedGdiFont
constructor.THIS MAY BREAK some existing scripts in a minor way, but for me it solved quite a lot of headaches while developing scripts.
So the default
fontSize
is now in PT units (as everywhere else in windows), and specifying a negative font size equals PX units.In conclusion
I suspect that this won't be a simple merge, and it will require some discussion and amendments on my part before being accepted to the main repository, and I'm very open to comments and suggestions on making this extensions a part of SMP.
(It is also worth noting that I'm developing a "naive" approach JS GUI library for drawing themed controls.)