Implement font customization options in MacOSX splash window

Also, switch to non-deprecated CoreText API
This commit is contained in:
rdb 2015-09-02 22:27:03 +02:00
parent be58900723
commit f9f62f17f1
2 changed files with 100 additions and 70 deletions

View File

@ -36,6 +36,7 @@ P3DOsxSplashWindow::
P3DOsxSplashWindow(P3DInstance *inst, bool make_visible) : P3DOsxSplashWindow(P3DInstance *inst, bool make_visible) :
P3DSplashWindow(inst, make_visible) P3DSplashWindow(inst, make_visible)
{ {
_font_attribs = NULL;
_install_progress = 0; _install_progress = 0;
_progress_known = true; _progress_known = true;
_received_data = 0; _received_data = 0;
@ -59,6 +60,9 @@ P3DOsxSplashWindow::
DisposeWindow(_toplevel_window); DisposeWindow(_toplevel_window);
_toplevel_window = NULL; _toplevel_window = NULL;
} }
if (_font_attribs != NULL) {
CFRelease(_font_attribs);
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -123,6 +127,41 @@ set_wparams(const P3DWindowParams &wparams) {
} }
} }
} }
// Determine the attributes of the font we're going to use.
int symbolic = 0;
if (_font_style != FS_normal) {
symbolic |= kCTFontItalicTrait;
}
if (_font_weight > 500) {
symbolic |= kCTFontBoldTrait;
}
CFNumberRef symbolic_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &symbolic);
CFStringRef traits_keys[1] = { kCTFontSymbolicTrait };
CFTypeRef traits_values[1] = { symbolic_ref };
CFDictionaryRef traits = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&traits_keys, (const void **)&traits_values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFStringRef family = CFStringCreateWithCString(NULL, _font_family.c_str(), kCFStringEncodingUTF8);
CFStringRef attribs_keys[2] = { kCTFontFamilyNameAttribute, kCTFontTraitsAttribute };
CFTypeRef attribs_values[2] = { family, traits };
CFDictionaryRef attribs = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&attribs_keys, (const void **)&attribs_values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
// Create the font object.
CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes(attribs);
CTFontRef font = CTFontCreateWithFontDescriptor(font_desc, _font_size, NULL);
CFStringRef keys[1] = { kCTFontAttributeName };
CFTypeRef values[1] = { font };
_font_attribs = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&keys, (const void **)&values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFRelease(font);
CFRelease(font_desc);
CFRelease(attribs);
CFRelease(traits);
CFRelease(family);
CFRelease(symbolic_ref);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -171,6 +210,9 @@ set_image_filename(const string &image_filename, ImagePlacement image_placement)
case IP_button_click: case IP_button_click:
load_image(_button_click_image, image_filename); load_image(_button_click_image, image_filename);
break; break;
default:
return;
} }
refresh(); refresh();
@ -333,10 +375,8 @@ paint_window_osx_cgcontext(CGContextRef context) {
CGColorRef bg = CGColorCreate(rgb_space, bg_components); CGColorRef bg = CGColorCreate(rgb_space, bg_components);
CGRect region = { { 0, 0 }, { _win_width, _win_height } }; CGRect region = { { 0, 0 }, { _win_width, _win_height } };
CGContextBeginPath(context);
CGContextSetFillColorWithColor(context, bg); CGContextSetFillColorWithColor(context, bg);
CGContextAddRect(context, region); CGContextFillRect(context, region);
CGContextFillPath(context);
CGColorRelease(bg); CGColorRelease(bg);
CGColorSpaceRelease(rgb_space); CGColorSpaceRelease(rgb_space);
@ -445,8 +485,6 @@ handle_event_osx_event_record(const P3D_event_data &event) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool P3DOsxSplashWindow:: bool P3DOsxSplashWindow::
handle_event_osx_cocoa(const P3D_event_data &event) { handle_event_osx_cocoa(const P3D_event_data &event) {
bool retval = false;
assert(event._event_type == P3D_ET_osx_cocoa); assert(event._event_type == P3D_ET_osx_cocoa);
const P3DCocoaEvent &ce = event._event._osx_cocoa._event; const P3DCocoaEvent &ce = event._event._osx_cocoa._event;
@ -455,33 +493,31 @@ handle_event_osx_cocoa(const P3D_event_data &event) {
if (_visible) { if (_visible) {
CGContextRef context = ce.data.draw.context; CGContextRef context = ce.data.draw.context;
paint_window_osx_cgcontext(context); paint_window_osx_cgcontext(context);
retval = true; return true;
} else {
return false;
} }
break;
case P3DCocoaEventMouseDown: case P3DCocoaEventMouseDown:
set_mouse_data((int)ce.data.mouse.pluginX, (int)ce.data.mouse.pluginY, true); set_mouse_data((int)ce.data.mouse.pluginX, (int)ce.data.mouse.pluginY, true);
retval = true; return true;
break;
case P3DCocoaEventMouseUp: case P3DCocoaEventMouseUp:
set_mouse_data((int)ce.data.mouse.pluginX, (int)ce.data.mouse.pluginY, false); set_mouse_data((int)ce.data.mouse.pluginX, (int)ce.data.mouse.pluginY, false);
retval = true; return true;
break;
case P3DCocoaEventMouseMoved: case P3DCocoaEventMouseMoved:
case P3DCocoaEventMouseDragged: case P3DCocoaEventMouseDragged:
set_mouse_data((int)ce.data.mouse.pluginX, (int)ce.data.mouse.pluginY, _mouse_down); set_mouse_data((int)ce.data.mouse.pluginX, (int)ce.data.mouse.pluginY, _mouse_down);
retval = true; return true;
break;
case P3DCocoaEventFocusChanged: case P3DCocoaEventFocusChanged:
_mouse_active = (ce.data.focus.hasFocus != 0); _mouse_active = (ce.data.focus.hasFocus != 0);
retval = true; return true;
break;
}
return retval; default:
return false;
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -612,42 +648,33 @@ paint_image(CGContextRef context, const OsxImageData &image) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void P3DOsxSplashWindow:: void P3DOsxSplashWindow::
paint_progress_bar(CGContextRef context) { paint_progress_bar(CGContextRef context) {
// Get some colors we'll need. We can't just use
// CGColorGetConstantColor(), since that requires 10.5.
CGFloat fg_components[] = { _fgcolor_r / 255.0f, _fgcolor_g / 255.0f, _fgcolor_b / 255.0f, 1 }; CGFloat fg_components[] = { _fgcolor_r / 255.0f, _fgcolor_g / 255.0f, _fgcolor_b / 255.0f, 1 };
CGFloat bg_components[] = { _bgcolor_r / 255.0f, _bgcolor_g / 255.0f, _bgcolor_b / 255.0f, 1 }; CGFloat bg_components[] = { _bgcolor_r / 255.0f, _bgcolor_g / 255.0f, _bgcolor_b / 255.0f, 1 };
CGFloat bar_components[] = { _barcolor_r / 255.0f, _barcolor_g / 255.0f, _barcolor_b / 255.0f, 1 }; CGFloat bar_components[] = { _barcolor_r / 255.0f, _barcolor_g / 255.0f, _barcolor_b / 255.0f, 1 };
CGFloat bar_bg_components[] = { _bar_bgcolor_r / 255.0f, _bar_bgcolor_g / 255.0f, _bar_bgcolor_b / 255.0f, 1 };
CGColorSpaceRef rgb_space = CGColorSpaceCreateDeviceRGB(); CGColorSpaceRef rgb_space = CGColorSpaceCreateDeviceRGB();
CGColorRef fg = CGColorCreate(rgb_space, fg_components); CGColorRef fg = CGColorCreate(rgb_space, fg_components);
CGColorRef bg = CGColorCreate(rgb_space, bg_components); CGColorRef bg = CGColorCreate(rgb_space, bg_components);
CGColorRef bar = CGColorCreate(rgb_space, bar_components); CGColorRef bar = CGColorCreate(rgb_space, bar_components);
CGColorRef bar_bg = CGColorCreate(rgb_space, bar_bg_components);
// Get the proper placement for the progress bar.
int bar_x, bar_y, bar_width, bar_height; int bar_x, bar_y, bar_width, bar_height;
get_bar_placement(bar_x, bar_y, bar_width, bar_height); get_bar_placement(bar_x, bar_y, bar_width, bar_height);
// We offset the bar by half a pixel, so we'll be drawing the CGRect bar_rect = { { bar_x, bar_y }, { bar_width, bar_height } };
// one-pixel line through the middle of a pixel, and it won't try to
// antialias itself into a half-black two-pixel line.
float bar_xf = bar_x + 0.5;
float bar_yf = bar_y - 0.5;
CGRect bar_rect = { { bar_xf, bar_yf }, { bar_width, bar_height } };
// Clear the entire progress bar to white (or the background color). // Clear the entire progress bar to white (or the background color).
CGContextBeginPath(context); CGContextSetFillColorWithColor(context, bar_bg);
CGContextSetFillColorWithColor(context, bg); CGContextFillRect(context, bar_rect);
CGContextAddRect(context, bar_rect);
CGContextFillPath(context);
// Draw the interior of the progress bar in blue (or the bar color). // Draw the interior of the progress bar in blue (or the bar color).
if (_progress_known) { if (_progress_known) {
int progress_width = (int)(bar_width * _install_progress + 0.5); int progress_width = (int)(bar_width * _install_progress + 0.5);
if (progress_width != 0) { if (progress_width != 0) {
CGRect prog = { { bar_xf, bar_yf }, { progress_width, bar_height } }; CGRect prog = { { bar_x, bar_y }, { progress_width, bar_height } };
CGContextBeginPath(context);
CGContextSetFillColorWithColor(context, bar); CGContextSetFillColorWithColor(context, bar);
CGContextAddRect(context, prog); CGContextFillRect(context, prog);
CGContextFillPath(context);
} }
} else { } else {
// Progress is unknown. Draw a moving block, not a progress bar // Progress is unknown. Draw a moving block, not a progress bar
@ -660,57 +687,58 @@ paint_progress_bar(CGContextRef context) {
progress = block_travel * 2 - progress; progress = block_travel * 2 - progress;
} }
CGRect prog = { { bar_xf + progress, bar_yf }, { block_width, bar_height } }; CGRect prog = { { bar_x + progress, bar_y }, { block_width, bar_height } };
CGContextBeginPath(context);
CGContextSetFillColorWithColor(context, bar); CGContextSetFillColorWithColor(context, bar);
CGContextAddRect(context, prog); CGContextFillRect(context, prog);
CGContextFillPath(context);
} }
// Draw the black stroke around the progress bar. // Draw the black stroke around the progress bar.
CGContextBeginPath(context); if (_bar_border > 0) {
CGContextSetLineWidth(context, 1); // We offset the border by half a pixel, so we'll be drawing the
CGContextSetStrokeColorWithColor(context, fg); // one-pixel line through the middle of a pixel, and it won't try to
CGContextAddRect(context, bar_rect); // antialias itself into a half-black two-pixel line.
CGContextStrokePath(context); CGRect border_rect = { { bar_x - 0.5, bar_y - 0.5 },
{ bar_width + 1, bar_height + 1 } };
CGContextBeginPath(context);
CGContextSetLineWidth(context, 1);
CGContextSetStrokeColorWithColor(context, fg);
for (int i = 0; i < _bar_border; ++i) {
CGContextAddRect(context, border_rect);
border_rect.origin.x -= 1;
border_rect.origin.y -= 1;
border_rect.size.width += 2;
border_rect.size.height += 2;
}
CGContextStrokePath(context);
}
if (!_install_label.empty()) { if (!_install_label.empty()) {
// Now draw the install_label right above it.
// Need to invert the text so it won't be upside-down. // Need to invert the text so it won't be upside-down.
CGAffineTransform text_xform = CGAffineTransformMakeScale(1, -1); CGAffineTransform text_xform = CGAffineTransformMakeScale(1, -1);
CGContextSetTextMatrix(context, text_xform); CGContextSetTextMatrix(context, text_xform);
// Choose a suitable font. // Now draw the install_label right above it.
float text_height = 15.0; CFStringRef string = CFStringCreateWithCString(NULL, _install_label.c_str(), kCFStringEncodingUTF8);
CGContextSelectFont(context, _font_family.c_str(), text_height, kCGEncodingMacRoman); CFAttributedStringRef attr_string = CFAttributedStringCreate(NULL, string, _font_attribs);
CTLineRef line = CTLineCreateWithAttributedString(attr_string);
// Measure the text, for centering. // Determine the placement based on the size of the text.
CGContextSetTextPosition(context, 0, 0); CGRect bounds = CTLineGetImageBounds(line, context);
CGContextSetTextDrawingMode(context, kCGTextInvisible); float text_x = (_win_width - bounds.size.width) / 2.0f - bounds.origin.x;
CGContextShowText(context, _install_label.data(), _install_label.length()); float text_y = bar_y + bounds.origin.y - 4 - _bar_border;
CGPoint end_point = CGContextGetTextPosition(context);
float text_width = end_point.x;
int text_x = (int)(_win_width - text_width) / 2;
int text_y = (int)(bar_y - text_height * 1.5);
// Clear the rectangle behind the text to bg.
CGRect text_rect = { { text_x - 2, text_y - 2 }, { text_width + 4, text_height + 4 } };
CGContextBeginPath(context);
CGContextAddRect(context, text_rect);
CGContextSetFillColorWithColor(context, bg);
CGContextFillPath(context);
// And finally, draw the text. // And finally, draw the text.
CGContextSetTextDrawingMode(context, kCGTextFill); CGContextSetTextPosition(context, text_x, text_y);
CGContextSetFillColorWithColor(context, fg); CTLineDraw(line, context);
CGContextShowTextAtPoint(context, text_x, text_y + text_height, CFRelease(line);
_install_label.data(), _install_label.length()); CFRelease(attr_string);
CFRelease(string);
} }
CGColorRelease(bar_bg);
CGColorRelease(bar); CGColorRelease(bar);
CGColorRelease(bg); CGColorRelease(bg);
CGColorRelease(fg); CGColorRelease(fg);

View File

@ -83,6 +83,8 @@ private:
OsxImageData _button_rollover_image; OsxImageData _button_rollover_image;
OsxImageData _button_click_image; OsxImageData _button_click_image;
CFDictionaryRef _font_attribs;
string _install_label; string _install_label;
double _install_progress; double _install_progress;
bool _progress_known; bool _progress_known;