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;