Mercurial > dwindows
comparison ios/dw.m @ 2830:cc9258ba53d7
iOS: Remimplement the label and image view in the custom cell.
Using the built-in ones is apparently more trouble than it is worth.
author | bsmith@81767d24-ef19-dc11-ae90-00e081727c95 |
---|---|
date | Fri, 09 Sep 2022 08:42:22 +0000 |
parents | c543f7df7867 |
children | adb0e4ce9347 |
comparison
equal
deleted
inserted
replaced
2829:c543f7df7867 | 2830:cc9258ba53d7 |
---|---|
2335 */ | 2335 */ |
2336 @interface DWTableViewCell : UITableViewCell | 2336 @interface DWTableViewCell : UITableViewCell |
2337 { | 2337 { |
2338 NSMutableArray *columndata; | 2338 NSMutableArray *columndata; |
2339 UIStackView *stack; | 2339 UIStackView *stack; |
2340 UILabel *label; | |
2341 UIImageView *image; | |
2340 } | 2342 } |
2341 -(void)setColumnData:(NSMutableArray *)input; | 2343 -(void)setColumnData:(NSMutableArray *)input; |
2342 -(NSMutableArray *)columnData; | 2344 -(NSMutableArray *)columnData; |
2345 -(UIImageView *)image; | |
2346 -(UILabel *)label; | |
2343 @end | 2347 @end |
2344 | 2348 |
2345 @implementation DWTableViewCell | 2349 @implementation DWTableViewCell |
2350 -(id)init { | |
2351 self = [super init]; | |
2352 | |
2353 image = [[[UIImageView alloc] init] retain]; | |
2354 [image setTranslatesAutoresizingMaskIntoConstraints:NO]; | |
2355 [[self contentView] addSubview:image]; | |
2356 | |
2357 label = [[[UILabel alloc] init] retain]; | |
2358 [label setTranslatesAutoresizingMaskIntoConstraints:NO]; | |
2359 [[self contentView] addSubview:label]; | |
2360 | |
2361 stack = [[[UIStackView alloc] init] retain]; | |
2362 [stack setTranslatesAutoresizingMaskIntoConstraints:NO]; | |
2363 [stack setSpacing:5.0]; | |
2364 [[self contentView] addSubview:stack]; | |
2365 | |
2366 /* Let's use the default margins */ | |
2367 UILayoutGuide *g = [[self contentView] layoutMarginsGuide]; | |
2368 | |
2369 [NSLayoutConstraint activateConstraints:@[ | |
2370 /* Constrain label Top/Leading/Trailing to content margins guide */ | |
2371 [image.topAnchor constraintEqualToAnchor:g.topAnchor constant:0.0], | |
2372 [image.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:0.0], | |
2373 [image.trailingAnchor constraintEqualToAnchor:label.leadingAnchor constant:-4.0], | |
2374 [label.topAnchor constraintEqualToAnchor:g.topAnchor constant:0.0], | |
2375 [label.leadingAnchor constraintEqualToAnchor:image.trailingAnchor constant:4.0], | |
2376 /* No Height, because we'll use the label's intrinsic size */ | |
2377 | |
2378 /* Constrain stack view Top to label bottom plus 8-points */ | |
2379 [stack.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:0.0], | |
2380 /* Leading/Trailing/Bottom to content margins guide */ | |
2381 [stack.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:0.0], | |
2382 [stack.bottomAnchor constraintEqualToAnchor:g.bottomAnchor constant:0.0], | |
2383 /* No Height, because we'll use the arranged subviews heights */ | |
2384 ]]; | |
2385 return self; | |
2386 } | |
2387 -(UILabel *)label { return label; } | |
2388 -(UIImageView *)image { return image; } | |
2346 -(void)setColumnData:(NSMutableArray *)input | 2389 -(void)setColumnData:(NSMutableArray *)input |
2347 { | 2390 { |
2348 if(columndata != input) | 2391 if(columndata != input) |
2349 { | 2392 { |
2350 NSMutableArray *olddata = columndata; | 2393 NSMutableArray *olddata = columndata; |
2353 [olddata release]; | 2396 [olddata release]; |
2354 } | 2397 } |
2355 /* If we have columndata and are not in default mode */ | 2398 /* If we have columndata and are not in default mode */ |
2356 if(columndata && _dw_container_mode > DW_CONTAINER_MODE_DEFAULT) | 2399 if(columndata && _dw_container_mode > DW_CONTAINER_MODE_DEFAULT) |
2357 { | 2400 { |
2358 /* If we don't have a stack, create one */ | 2401 bool extra = _dw_container_mode == DW_CONTAINER_MODE_EXTRA; |
2359 if(!stack) | 2402 id subviews = [stack arrangedSubviews]; |
2360 { | 2403 int index = 0; |
2361 NSLayoutConstraint *constraint; | 2404 |
2362 | 2405 /* Extra mode stack is horizontal, multi stack is vertical */ |
2363 stack = [[[UIStackView alloc] init] retain]; | 2406 [stack setAxis:(extra ? UILayoutConstraintAxisHorizontal : UILayoutConstraintAxisVertical)]; |
2364 [stack setTranslatesAutoresizingMaskIntoConstraints:NO]; | 2407 |
2365 [stack setSpacing:5.0]; | 2408 /* Create the stack using columndata, reusing objects when possible */ |
2366 [[self contentView] addSubview:stack]; | 2409 for(id object in columndata) |
2367 | 2410 { |
2368 /* Leading */ | 2411 if([object isKindOfClass:[NSString class]]) |
2369 constraint = [NSLayoutConstraint constraintWithItem:stack attribute:NSLayoutAttributeLeft | |
2370 relatedBy:NSLayoutRelationEqual toItem:[self contentView] | |
2371 attribute:NSLayoutAttributeLeft multiplier: 1.0 constant:0.0]; | |
2372 [[self contentView] addConstraint:constraint]; | |
2373 | |
2374 /* Top */ | |
2375 constraint = [NSLayoutConstraint constraintWithItem:stack attribute:NSLayoutAttributeTop | |
2376 relatedBy:NSLayoutRelationEqual toItem:[self textLabel] | |
2377 attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]; | |
2378 [[self contentView] addConstraint:constraint]; | |
2379 } | |
2380 /* Extra and Multi modes create a stack with all the column data */ | |
2381 if(_dw_container_mode > DW_CONTAINER_MODE_DEFAULT) | |
2382 { | |
2383 bool extra = _dw_container_mode == DW_CONTAINER_MODE_EXTRA; | |
2384 id subviews = [stack arrangedSubviews]; | |
2385 int index = 0; | |
2386 | |
2387 /* Extra mode stack is horizontal, multi stack is vertical */ | |
2388 [stack setAxis:(extra ? UILayoutConstraintAxisHorizontal : UILayoutConstraintAxisVertical)]; | |
2389 | |
2390 /* Create the stack using columndata, reusing objects when possible */ | |
2391 for(id object in columndata) | |
2392 { | 2412 { |
2393 if([object isKindOfClass:[NSString class]]) | 2413 id label = nil; |
2414 | |
2415 /* Check if we already have a view, reuse it if possible.. */ | |
2416 if(index < [subviews count]) | |
2394 { | 2417 { |
2395 id label = nil; | 2418 id oldview = [subviews objectAtIndex:index]; |
2396 | 2419 |
2397 /* Check if we already have a view, reuse it if possible.. */ | 2420 if([oldview isMemberOfClass:(extra ? [UILabel class] : [UIButton class])]) |
2421 { | |
2422 label = oldview; | |
2423 /* If we are reusing a button, make sure the image is not set */ | |
2424 if(!extra) | |
2425 [label setImage:nil forState:UIControlStateNormal]; | |
2426 } | |
2427 else | |
2428 [stack removeArrangedSubview:oldview]; | |
2429 } | |
2430 if(!label) | |
2431 { | |
2432 label = extra ? [[UILabel alloc] init] : [UIButton buttonWithType:UIButtonTypeCustom]; | |
2433 | |
2434 [label setTranslatesAutoresizingMaskIntoConstraints:NO]; | |
2435 if(extra) | |
2436 [label setTextAlignment:NSTextAlignmentCenter]; | |
2437 | |
2398 if(index < [subviews count]) | 2438 if(index < [subviews count]) |
2439 [stack insertArrangedSubview:label atIndex:index]; | |
2440 else /* Remove the view if it won't work */ | |
2441 [stack addArrangedSubview:label]; | |
2442 } | |
2443 /* Set the label or button text/title */ | |
2444 if(extra) | |
2445 [label setText:object]; | |
2446 else | |
2447 [label setTitle:object forState:UIControlStateNormal]; | |
2448 index++; | |
2449 } | |
2450 else if([object isMemberOfClass:[UIImage class]]) | |
2451 { | |
2452 id image = nil; | |
2453 | |
2454 /* Check if we already have a view, reuse it if possible.. */ | |
2455 if(index < [subviews count]) | |
2456 { | |
2457 id oldview = [subviews objectAtIndex:index]; | |
2458 | |
2459 if([oldview isMemberOfClass:(extra ? [UIImageView class] : [UIButton class])]) | |
2399 { | 2460 { |
2400 id oldview = [subviews objectAtIndex:index]; | 2461 image = oldview; |
2401 | 2462 /* If we are reusing a button, make sure the text is not set */ |
2402 if([oldview isMemberOfClass:(extra ? [UILabel class] : [UIButton class])]) | 2463 if(!extra) |
2403 { | 2464 [image setTitle:nil forState:UIControlStateNormal]; |
2404 label = oldview; | |
2405 /* If we are reusing a button, make sure the image is not set */ | |
2406 if(!extra) | |
2407 [label setImage:nil forState:UIControlStateNormal]; | |
2408 } | |
2409 else | |
2410 [stack removeArrangedSubview:oldview]; | |
2411 } | 2465 } |
2412 if(!label) | 2466 else /* Remove the view if it won't work */ |
2413 { | 2467 [stack removeArrangedSubview:oldview]; |
2414 label = extra ? [[UILabel alloc] init] : [UIButton buttonWithType:UIButtonTypeCustom]; | 2468 } |
2415 | 2469 if(!image) |
2416 [label setTranslatesAutoresizingMaskIntoConstraints:NO]; | 2470 { |
2417 if(extra) | 2471 image = extra ? [[UIImageView alloc] init] : [UIButton buttonWithType:UIButtonTypeCustom]; |
2418 [label setTextAlignment:NSTextAlignmentCenter]; | 2472 |
2419 | 2473 [image setTranslatesAutoresizingMaskIntoConstraints:NO]; |
2420 if(index < [subviews count]) | 2474 |
2421 [stack insertArrangedSubview:label atIndex:index]; | 2475 if(index < [subviews count]) |
2422 else /* Remove the view if it won't work */ | 2476 [stack insertArrangedSubview:image atIndex:index]; |
2423 [stack addArrangedSubview:label]; | |
2424 } | |
2425 /* Set the label or button text/title */ | |
2426 if(extra) | |
2427 [label setText:object]; | |
2428 else | 2477 else |
2429 [label setTitle:object forState:UIControlStateNormal]; | 2478 [stack addArrangedSubview:image]; |
2430 index++; | |
2431 } | 2479 } |
2432 else if([object isMemberOfClass:[UIImage class]]) | 2480 /* Set the image view or button image */ |
2433 { | 2481 if(extra) |
2434 id image = nil; | 2482 [image setImage:object]; |
2435 | 2483 else |
2436 /* Check if we already have a view, reuse it if possible.. */ | 2484 [image setImage:image forState:UIControlStateNormal]; |
2437 if(index < [subviews count]) | 2485 |
2438 { | 2486 index++; |
2439 id oldview = [subviews objectAtIndex:index]; | |
2440 | |
2441 if([oldview isMemberOfClass:(extra ? [UIImageView class] : [UIButton class])]) | |
2442 { | |
2443 image = oldview; | |
2444 /* If we are reusing a button, make sure the text is not set */ | |
2445 if(!extra) | |
2446 [image setTitle:nil forState:UIControlStateNormal]; | |
2447 } | |
2448 else /* Remove the view if it won't work */ | |
2449 [stack removeArrangedSubview:oldview]; | |
2450 } | |
2451 if(!image) | |
2452 { | |
2453 image = extra ? [[UIImageView alloc] init] : [UIButton buttonWithType:UIButtonTypeCustom]; | |
2454 | |
2455 [image setTranslatesAutoresizingMaskIntoConstraints:NO]; | |
2456 | |
2457 if(index < [subviews count]) | |
2458 [stack insertArrangedSubview:image atIndex:index]; | |
2459 else | |
2460 [stack addArrangedSubview:image]; | |
2461 } | |
2462 /* Set the image view or button image */ | |
2463 if(extra) | |
2464 [image setImage:object]; | |
2465 else | |
2466 [image setImage:image forState:UIControlStateNormal]; | |
2467 | |
2468 index++; | |
2469 } | |
2470 } | 2487 } |
2471 } | 2488 } |
2472 } | 2489 } |
2473 } | 2490 } |
2474 -(NSMutableArray *)columnData { return columndata; } | 2491 -(NSMutableArray *)columnData { return columndata; } |
2475 -(void)dealloc { [columndata release]; [super dealloc]; [stack removeFromSuperview]; [stack release]; } | 2492 -(void)dealloc |
2493 { | |
2494 [columndata release]; | |
2495 [image removeFromSuperview]; | |
2496 [image release]; | |
2497 [label removeFromSuperview]; | |
2498 [label release]; | |
2499 [stack removeFromSuperview]; | |
2500 [stack release]; | |
2501 [super dealloc]; | |
2502 } | |
2476 @end | 2503 @end |
2477 | 2504 |
2478 /* Create a tableview cell for containers using DW_CONTAINER_MODE_* or listboxes */ | 2505 /* Create a tableview cell for containers using DW_CONTAINER_MODE_* or listboxes */ |
2479 DWTableViewCell *_dw_table_cell_view_new(UIImage *icon, NSString *text, NSMutableArray *columndata) | 2506 DWTableViewCell *_dw_table_cell_view_new(UIImage *icon, NSString *text, NSMutableArray *columndata) |
2480 { | 2507 { |
2481 DWTableViewCell *browsercell = [[DWTableViewCell alloc] init]; | 2508 DWTableViewCell *browsercell = [[DWTableViewCell alloc] init]; |
2482 [browsercell setAutoresizesSubviews:YES]; | 2509 [browsercell setAutoresizesSubviews:YES]; |
2483 | 2510 |
2484 if(icon) | 2511 if(icon) |
2485 [[browsercell imageView] setImage:icon]; | 2512 [[browsercell image] setImage:icon]; |
2486 if(text) | 2513 if(text) |
2487 [[browsercell textLabel] setText:text]; | 2514 [[browsercell label] setText:text]; |
2488 if(columndata) | 2515 if(columndata) |
2489 [browsercell setColumnData:columndata]; | 2516 [browsercell setColumnData:columndata]; |
2490 return browsercell; | 2517 return browsercell; |
2491 } | 2518 } |
2492 | 2519 |
2547 { | 2574 { |
2548 /* Not reusing cell views, so get the cell from our array */ | 2575 /* Not reusing cell views, so get the cell from our array */ |
2549 int index = (int)indexPath.row; | 2576 int index = (int)indexPath.row; |
2550 id celldata = [data objectAtIndex:index]; | 2577 id celldata = [data objectAtIndex:index]; |
2551 | 2578 |
2552 /* The data is already a NSTableCellView so just return that */ | 2579 /* The data is already a DWTableViewCell so just return that */ |
2553 if([celldata isMemberOfClass:[DWTableViewCell class]]) | 2580 if([celldata isMemberOfClass:[DWTableViewCell class]]) |
2554 { | 2581 { |
2555 DWTableViewCell *result = celldata; | 2582 DWTableViewCell *result = celldata; |
2556 | 2583 |
2557 /* Copy the alignment setting from the column, | 2584 /* Copy the alignment setting from the column, |
2558 * and set the text color from the container. | 2585 * and set the text color from the container. |
2559 */ | 2586 */ |
2560 if(fgcolor) | 2587 if(fgcolor) |
2561 [[result textLabel] setTextColor:fgcolor]; | 2588 [[result label] setTextColor:fgcolor]; |
2562 | 2589 |
2563 /* Return the result */ | 2590 /* Return the result */ |
2564 return result; | 2591 return result; |
2565 } | 2592 } |
2566 return nil; | 2593 return nil; |
2579 if(oddcolor) | 2606 if(oddcolor) |
2580 [cell setBackgroundColor:oddcolor]; | 2607 [cell setBackgroundColor:oddcolor]; |
2581 else | 2608 else |
2582 [cell setBackgroundColor:[UIColor clearColor]]; | 2609 [cell setBackgroundColor:[UIColor clearColor]]; |
2583 } | 2610 } |
2611 } | |
2612 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath | |
2613 { | |
2614 int index = (int)indexPath.row; | |
2615 id cell = [data objectAtIndex:index]; | |
2616 CGFloat height = 0.0; | |
2617 | |
2618 /* The data is already a DWTableViewCell so just return that */ | |
2619 if([cell isMemberOfClass:[DWTableViewCell class]]) | |
2620 { | |
2621 height = [[cell contentView] systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; | |
2622 NSLog(@"Calculated height %f\n", (float)height); | |
2623 } | |
2624 return height > 0.0 ? height : UITableViewAutomaticDimension; | |
2625 } | |
2626 -(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath | |
2627 { | |
2628 return _dw_container_mode > DW_CONTAINER_MODE_DEFAULT ? 85.0 : 44.0; | |
2584 } | 2629 } |
2585 -(UIContextMenuConfiguration *)tableView:(UITableView *)tableView contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point | 2630 -(UIContextMenuConfiguration *)tableView:(UITableView *)tableView contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point |
2586 { | 2631 { |
2587 DWWindow *window = (DWWindow *)[self window]; | 2632 DWWindow *window = (DWWindow *)[self window]; |
2588 UIContextMenuConfiguration *config = nil; | 2633 UIContextMenuConfiguration *config = nil; |
2794 DWTableViewCell *cell = [data objectAtIndex:(x*colcount)]; | 2839 DWTableViewCell *cell = [data objectAtIndex:(x*colcount)]; |
2795 int thiswidth = 4, thisheight = 0; | 2840 int thiswidth = 4, thisheight = 0; |
2796 | 2841 |
2797 if([cell imageView]) | 2842 if([cell imageView]) |
2798 { | 2843 { |
2799 thiswidth += [[cell imageView] image].size.width; | 2844 thiswidth += [[cell image] image].size.width; |
2800 thisheight = [[cell imageView] image].size.height; | 2845 thisheight = [[cell image] image].size.height; |
2801 } | 2846 } |
2802 if([cell textLabel]) | 2847 if([cell textLabel]) |
2803 { | 2848 { |
2804 int textheight = [[cell textLabel] intrinsicContentSize].width; | 2849 int textheight = [[cell label] intrinsicContentSize].width; |
2805 thiswidth += [[cell textLabel] intrinsicContentSize].width; | 2850 thiswidth += [[cell label] intrinsicContentSize].width; |
2806 if(textheight > thisheight) | 2851 if(textheight > thisheight) |
2807 thisheight = textheight; | 2852 thisheight = textheight; |
2808 } | 2853 } |
2809 | 2854 |
2810 cheight += thisheight; | 2855 cheight += thisheight; |
5614 | 5659 |
5615 [cont setAllowsMultipleSelection:(multi ? YES : NO)]; | 5660 [cont setAllowsMultipleSelection:(multi ? YES : NO)]; |
5616 [cont setDataSource:cont]; | 5661 [cont setDataSource:cont]; |
5617 [cont setDelegate:cont]; | 5662 [cont setDelegate:cont]; |
5618 [cont setTag:cid]; | 5663 [cont setTag:cid]; |
5664 [cont setRowHeight:UITableViewAutomaticDimension]; | |
5665 [cont setEstimatedRowHeight:(_dw_container_mode > DW_CONTAINER_MODE_DEFAULT ? 85.0 : 44.0)]; | |
5619 [cont setRowBgOdd:DW_RGB_TRANSPARENT andEven:DW_RGB_TRANSPARENT]; | 5666 [cont setRowBgOdd:DW_RGB_TRANSPARENT andEven:DW_RGB_TRANSPARENT]; |
5620 return cont; | 5667 return cont; |
5621 } | 5668 } |
5622 | 5669 |
5623 /* | 5670 /* |
5865 *buffer = '\0'; | 5912 *buffer = '\0'; |
5866 } | 5913 } |
5867 else | 5914 else |
5868 { | 5915 { |
5869 DWTableViewCell *cell = [cont getRow:index]; | 5916 DWTableViewCell *cell = [cont getRow:index]; |
5870 NSString *nstr = [[cell textLabel] text]; | 5917 NSString *nstr = [[cell label] text]; |
5871 | 5918 |
5872 strncpy(buffer, [nstr UTF8String], length - 1); | 5919 strncpy(buffer, [nstr UTF8String], length - 1); |
5873 } | 5920 } |
5874 } | 5921 } |
5875 DW_FUNCTION_RETURN_NOTHING; | 5922 DW_FUNCTION_RETURN_NOTHING; |
5904 if(index <= count) | 5951 if(index <= count) |
5905 { | 5952 { |
5906 NSString *nstr = [NSString stringWithUTF8String:buffer]; | 5953 NSString *nstr = [NSString stringWithUTF8String:buffer]; |
5907 DWTableViewCell *cell = [cont getRow:index]; | 5954 DWTableViewCell *cell = [cont getRow:index]; |
5908 | 5955 |
5909 [[cell textLabel] setText:nstr]; | 5956 [[cell label] setText:nstr]; |
5910 [cont reloadData]; | 5957 [cont reloadData]; |
5911 [cont setNeedsDisplay]; | 5958 [cont setNeedsDisplay]; |
5912 } | 5959 } |
5913 } | 5960 } |
5914 DW_FUNCTION_RETURN_NOTHING; | 5961 DW_FUNCTION_RETURN_NOTHING; |
7347 DWTableViewCell *cell = object; | 7394 DWTableViewCell *cell = object; |
7348 | 7395 |
7349 if(column == 0) | 7396 if(column == 0) |
7350 { | 7397 { |
7351 if(icon) | 7398 if(icon) |
7352 [[cell imageView] setImage:icon]; | 7399 [[cell image] setImage:icon]; |
7353 else | 7400 else |
7354 [[cell textLabel] setText:text]; | 7401 [[cell label] setText:text]; |
7355 } | 7402 } |
7356 else if(icon || text) | 7403 else if(icon || text) |
7357 { | 7404 { |
7358 NSMutableArray *cd = [cell columnData]; | 7405 NSMutableArray *cd = [cell columnData]; |
7359 | 7406 |
7452 if([object isMemberOfClass:[DWTableViewCell class]]) | 7499 if([object isMemberOfClass:[DWTableViewCell class]]) |
7453 { | 7500 { |
7454 DWTableViewCell *cell = object; | 7501 DWTableViewCell *cell = object; |
7455 | 7502 |
7456 if(icon) | 7503 if(icon) |
7457 [[cell imageView] setImage:icon]; | 7504 [[cell image] setImage:icon]; |
7458 if(text) | 7505 if(text) |
7459 [[cell textLabel] setText:text]; | 7506 [[cell label] setText:text]; |
7460 } | 7507 } |
7461 else /* Otherwise replace it with a new cell */ | 7508 else /* Otherwise replace it with a new cell */ |
7462 [cont editCell:_dw_table_cell_view_new(icon, text, nil) at:(row+lastadd)]; | 7509 [cont editCell:_dw_table_cell_view_new(icon, text, nil) at:(row+lastadd)]; |
7463 [cont setNeedsDisplay]; | 7510 [cont setNeedsDisplay]; |
7464 DW_FUNCTION_RETURN_NOTHING; | 7511 DW_FUNCTION_RETURN_NOTHING; |